Пример #1
0
 /// <summary>Creates a new instance of NodeDestDistInt.</summary>
 /// <param name="node">The source Node.</param>
 /// <param name="dest">The destination of the new node.</param>
 /// <param name="dist">The distance from the source node to the nearest intersection.</param>
 /// <param name="intersections">The number of intersections.</param>
 public NodeDestDistInt(Node node, VectorF dest, FInt dist, int intersections)
 {
     this.Node = node;
     this.Dest = dest;
     this.Dist = dist;
     this.Intersections = intersections;
 }
Пример #2
0
 public static FInt Abs(FInt F)
 {
     if (F < FInt.F0)
         return F.Inverse;
     else
         return F;
 }
Пример #3
0
 /// <summary>Resets all values to their defaults.</summary>
 public virtual void clear()
 {
     IsParent = false;
     Radius = FInt.F0;
     Spacing = FInt.F0;
     GenSpacing = FInt.F0;
     SightDistance = FInt.F0;
 }
Пример #4
0
		/// <summary>
		/// Create a fixed-int number from parts.  For example, to create 1.5 pass in 1 and 500.
		/// </summary>
		/// <param name="PreDecimal">The number above the decimal.  For 1.5, this would be 1.</param>
		/// <param name="PostDecimal">The number below the decimal, to three digits.  
		/// For 1.5, this would be 500. For 1.005, this would be 5.</param>
		/// <returns>A fixed-int representation of the number parts</returns>
		public static FInt FromParts(int PreDecimal, int PostDecimal)
		{
			FInt f = new FInt(PreDecimal, true);
			if (PostDecimal != 0)
				f.RawValue += (new FInt(PostDecimal) / 1000).RawValue;

			return f;
		}
Пример #5
0
        public static FInt Asin(FInt F)
        {
            bool isNegative = F < 0;
            F = Abs(F);
            #if DEBUG
            if (F > FInt.OneF)
                throw new ArithmeticException("Bad Asin Input:" + F.ToDouble());
            #endif

            FInt f1 = ((((new FInt(145103 >> FInt.SHIFT_AMOUNT, false) * F) -
                new FInt(599880 >> FInt.SHIFT_AMOUNT, false) * F) +
                new FInt(1420468 >> FInt.SHIFT_AMOUNT, false) * F) -
                new FInt(3592413 >> FInt.SHIFT_AMOUNT, false) * F) +
                new FInt(26353447 >> FInt.SHIFT_AMOUNT, false);
            FInt f2 = PI / new FInt(2, true) - (Sqrt(FInt.OneF - F) * f1);

            return isNegative ? f2.Inverse : f2;
        }
Пример #6
0
        public static FInt Atan2(FInt F1, FInt F2)
        {
            if (F2.RawValue == 0 && F1.RawValue == 0)
                return (FInt)0;

            FInt result = (FInt)0;
            if (F2 > 0)
                result = Atan(F1 / F2);
            else if (F2 < 0)
            {
                if (F1 >= 0)
                    result = (PI - Atan(Abs(F1 / F2)));
                else
                    result = (PI - Atan(Abs(F1 / F2))).Inverse;
            }
            else
                result = (F1 >= 0 ? PI : PI.Inverse) / new FInt(2, true);

            return result;
        }
Пример #7
0
 /// <summary>Clones the provided segment.  All references to other nodes or segments are deep.</summary>
 /// <param name="toClone">The segment to clone.</param>
 public Segment(Segment toClone)
     : this(toClone.InWorld)
 {
     this.ID = toClone.ID;
     this.EndLoc = (VectorF[])toClone.EndLoc.Clone();
     this.CurLength = toClone.CurLength;
     this.State = (SegState[])toClone.State.Clone();
     this.owner = toClone.Owner;
     this.Length = toClone.Length;
     this.EndLength = (FInt[])toClone.EndLength.Clone();
     this.Nodes = (Node[])toClone.Nodes.Clone();
     this.People[0] = toClone.People[0].Clone();
     this.People[1] = toClone.People[1].Clone();
     this.NumPeople = toClone.NumPeople;
     this.Capacity = toClone.Capacity;
     this.CurCapacity = toClone.CurCapacity;
     this.curLaneCapacity = toClone.CurLaneCapacity;
     this.Direction = toClone.Direction;
     this.DirectionPerp = toClone.DirectionPerp;
     this.Angle = toClone.Angle;
     this.Destroyed = toClone.Destroyed;
 }
Пример #8
0
        /// <summary>Searches for a collision between the provided node and any node, segment, or geo.  Ignores collisions with the specified segments and nodes.</summary>
        /// <param name="center">The center of the node.</param>
        /// <param name="radius">The radius of the node.</param>
        /// <param name="ignoreSeg">The segments to ignore.</param>
        /// <param name="ignoreNode">The nodes to ignore.</param>
        /// <param name="includeUnbuilt">Whether or not to test against unfinished nodes or segments owned by a certain player.</param>
        /// <param name="owner">The owner of the unbuilt nodes and segments to test against.</param>
        /// <returns>Whether or not there was a collision.</returns>
        public bool nodeCollision(VectorF center, FInt radius, List<SegmentSkel> ignoreSeg, List<NodeSkel> ignoreNode, bool includeUnbuilt, Player owner)
        {
            List<SegmentSkel> segColls = new List<SegmentSkel>(1);
            List<NodeSkel> nodeColls = new List<NodeSkel>(1);
            List<GeoSkel> geoColls = new List<GeoSkel>(1);

            object[] array = new object[7];
            array[0] = center;
            array[1] = radius;
            array[4] = CollSrchType.DoesItCollide;
            array[5] = includeUnbuilt;
            array[6] = owner;

            // first look for collisions with nodes
            array[2] = ignoreNode;
            array[3] = nodeColls;
            Grid.PointExpand(center, array, gridNodeCollNode);

            if (nodeColls.Count == 0)
            {
                // next look for collisions with segments
                array[2] = ignoreSeg;
                array[3] = segColls;
                Grid.PointExpand(center, array, gridNodeCollSeg);

                if (segColls.Count == 0)
                {
                    // next look for collisions with geos
                    array[2] = null;
                    array[3] = geoColls;
                    Grid.PointExpand(center, array, gridNodeCollGeo);
                }
            }

            return nodeColls.Count > 0 || segColls.Count > 0 || geoColls.Count > 0;
        }
Пример #9
0
 private static FInt mul(FInt F1, FInt F2)
 {
     return F1 * F2;
 }
Пример #10
0
 public static FInt Sqrt(FInt f)
 {
     byte numberOfIterations = 8;
     if (f.RawValue > 0x64000)
         numberOfIterations = 12;
     if (f.RawValue > 0x3e8000)
         numberOfIterations = 16;
     return Sqrt(f, numberOfIterations);
 }
Пример #11
0
 public static FInt Tan(FInt i)
 {
     return Sin(i) / Cos(i);
 }
Пример #12
0
        public static FInt Sin(FInt i)
        {
            FInt j = (FInt)0;

            for (; i < 0; i += F25736) ;
            if (i > F25736)
                i %= F25736;
            FInt k = (i * F10) / F714;
            if (i != 0 && i != F6434 && i != PI &&
                i != F19302 && i != F25736)
                j = (i * F100) / F714 - k * F10;
            if (k <= F90)
                return sin_lookup(k, j);
            if (k <= F180)
                return sin_lookup(F180 - k, j);
            if (k <= F270)
                return sin_lookup(k - F180, j).Inverse;
            else
                return sin_lookup(F360 - k, j).Inverse;
        }
Пример #13
0
        public static FInt Sqrt(FInt f, int NumberOfIterations)
        {
            if (f.RawValue < 0) //NaN in Math.Sqrt
                throw new ArithmeticException("Input Error");
            if (f.RawValue == 0)
                return (FInt)0;
            FInt k = f + FInt.OneF >> 1;
            for (int i = 0; i < NumberOfIterations; i++)
                k = (k + (f / k)) >> 1;

            if (k.RawValue < 0)
                throw new ArithmeticException("Overflow");
            else
                return k;
        }
Пример #14
0
 /// <summary>Finds the length of the adjacent edge in a right triangle.</summary>
 /// <param name="hyp">The length of the hypotenuse of the triangle.</param>
 /// <param name="opp">The length of the opposite edge of the triangle.</param>
 /// <returns>The length of the adjacent edge in a right triangle.</returns>
 public static FInt getAdj(FInt hyp, FInt opp)
 {
     return Calc.Sqrt((hyp * hyp) - (opp * opp));
 }
Пример #15
0
 /// <summary>Rounds the decimal (if there is one) up</summary>
 /// <param name="num">The number to round up</param>
 /// <returns>The supplied number rounded up</returns>
 public static FInt RoundUp(FInt num)
 {
     FInt roundDown = (FInt)(int)num;
     return (roundDown != num)
         ? roundDown + FInt.F1
         : num;
 }
Пример #16
0
        /// <summary>Updates this segment.</summary>
        /// <param name="elapsed">The time elapsed since the last update.</param>
        public void update(FInt elapsed)
        {
            bool updateVisibility = false;

            // update segment activity
            for (int i = 0; i < 2; i++)
            {
                switch (State[i])
                {
                    case SegState.Complete:
                    case SegState.Building:
                        // do nothing
                        break;
                    case SegState.Retracting:
                        EndLength[i] -= InWorld.RetractSpeed * elapsed;
                        refreshEndLoc(1 - i);
                        updateVisibility = true;
                        InWorld.addEvent(ID, WorldEvent.EventType.SegChangeState);
                        break;
                    default:
                        throw new Exception("Unrecognized segment state: " + State[i].ToString());
                }
            }

            // update person activity
            FInt speed = (CurCapacity == 0) ? InWorld.PersonSpeedLower : (Calc.Min(InWorld.PersonSpeedUpper, ((People[0].Count + People[1].Count) / CurCapacity * InWorld.PersonSpeedRange + InWorld.PersonSpeedLower)) * elapsed);
            for (int i = 0; i < 2; i++)
            {
                bool removeLast = false;

                for (LListNode<FInt> person = People[i].Last; person != null; person = person.Previous)
                {
                    if (removeLast)
                        People[i].RemoveLast();

                    removeLast = false;

                    person.Value += speed;

                    if (person.Value > EndLength[i])
                    {
                        switch (State[i])
                        {
                            case SegState.Complete:
                                Nodes[1 - i].addPerson(this);
                                break;
                            case SegState.Retracting:
                                addPerson(1 - i);
                                break;
                            case SegState.Building:
                                addPerson(1 - i);
                                buildLane(i);
                                break;
                            default:
                                throw new Exception("Unrecognized segment state: " + State[i].ToString());
                        }

                        removeLast = true;
                    }
                }

                if (removeLast)
                    People[i].RemoveLast();
            }

            NumPeople = People[0].Count + People[1].Count;

            // if retracting and length reaches zero...
            FInt netLength = EndLength[0] + EndLength[1];
            if (netLength < Length)
            {
                for (int i = 0; i < 2; i++)
                {
                    if (State[i] == SegState.Retracting)
                    {
                        switch (State[1 - i])
                        {
                            case SegState.Complete:
                                if (Nodes[i].Parents.Count > 0)
                                    Nodes[i].removeSegment(this, true, true); // if node, is okay, disconnect from it
                                else
                                    Nodes[i].destroy(); // if no parents, destroy node
                                break;
                            case SegState.Building:
                                if (!Nodes[i].Active) // if the segment was building towards an inactive node, destroy it
                                    Nodes[i].destroy();
                                break;
                            case SegState.Retracting:
                                // do nothing
                                break;
                        }

                        updateVisibility = false;
                        destroy();
                        break;
                    }
                }
            }

            // update the visibility
            if (updateVisibility && Owner.Type != Player.PlayerType.Human && Visible)
                Visible = InWorld.HumanPlayer.Fog.isVisible(this);

            // get rid of people overflow (once per segment per update)
            if (!Destroyed && NumPeople > CurCapacity)
            {
                // see if there is an eligible person to remove
                int rLane = -1;

                for (rLane = 0; rLane < 2; rLane++)
                {
                    LListNode<FInt> first = People[rLane].First;

                    if (first != null &&
                        ((first.Value < Length - EndLength[1 - rLane]) ||
                        (State[0] != SegState.Complete && State[1] != SegState.Complete && NumPeople == 1)))
                        break;
                }

                if (rLane < 2)
                {
                    // find a connected node
                    Node testNode = null;
                    for (int i = 0; i < 2; i++)
                    {
                        if (State[i] == SegState.Complete)
                        {
                            testNode = Nodes[1 - i];
                            break;
                        }
                    }

                    // find out if the entire system is overflowing
                    int totPeople = 0;
                    FInt totCapacity = FInt.F0;
                    if (testNode != null)
                    {
                        totPeople += testNode.PeopleToSort;
                        for (int i = 0; i < testNode.Segments.Length; i++)
                        {
                            if (testNode.Segments[i] != null)
                            {
                                totPeople += testNode.SegNumPeople[i];
                                totCapacity += testNode.SegCapacity[i];
                            }
                        }
                    }
                    else
                    {
                        totPeople = NumPeople;
                        totCapacity = CurCapacity;
                    }

                    // remove the person
                    if (totPeople > totCapacity)
                    {
                        People[rLane].RemoveFirst();
                        NumPeople--;

                        if (State[0] == SegState.Complete)
                            Nodes[1].alterDensity(-1, FInt.F0, this);

                        if (State[1] == SegState.Complete)
                            Nodes[0].alterDensity(-1, FInt.F0, this);
                    }
                }
            }
        }
Пример #17
0
 public static FInt Min(FInt F1, FInt F2)
 {
     if (F1.RawValue < F2.RawValue)
         return F1;
     return F2;
 }
Пример #18
0
        /// <summary>Adds an intersection to all edges that intersect the specified circle.</summary>
        /// <param name="point">The center of the circle.</param>
        /// <param name="radius">The radius of the circle.</param>
        /// <param name="toAdd">The number of intersections to add.</param>
        public void intersect(VectorF point, FInt radius, int toAdd)
        {
            VectorD pointD = (VectorD)point;
            double radiusD = (double)radius;

            int left = (int)((pointD.X - radiusD) / NodeSpacing.X);
            int top = (int)((pointD.Y - radiusD) / NodeSpacing.Y);
            int right = (int)Calc.RoundUp((pointD.X + radiusD) / NodeSpacing.X);
            int bottom = (int)Calc.RoundUp((pointD.Y + radiusD) / NodeSpacing.Y);

            for (int row = top; row <= bottom; row++)
            {
                double y = (double)row * NodeSpacing.Y;

                for (int col = left; col <= right; col++)
                {
                    VectorD tl = new VectorD((double)col * NodeSpacing.X, y);
                    double nx = tl.X + NodeSpacing.X;
                    double ny = tl.Y + NodeSpacing.Y;

                    if (Calc.LinePointDistance(pointD, tl, new VectorD(tl.X, ny), NodeSpacing.Y) <= radiusD)
                        intersect(Grid[row, col], Grid[row + 1, col], toAdd);
                    if (Calc.LinePointDistance(pointD, tl, new VectorD(nx, y), NodeSpacing.X) <= radiusD)
                        intersect(Grid[row, col], Grid[row, col + 1], toAdd);
                    if (Calc.LinePointDistance(pointD, tl, new VectorD(nx, ny), crossEdgeLength) <= radiusD)
                        intersect(Grid[row, col], Grid[row + 1, col + 1], toAdd);
                    if (Calc.LinePointDistance(pointD, new VectorD(tl.X, ny), new VectorD(nx, y), crossEdgeLength) <= radiusD)
                        intersect(Grid[row + 1, col], Grid[row, col + 1], toAdd);
                }
            }
        }
Пример #19
0
        /// <summary>Gets the node type that may be built at the determined range.</summary>
        /// <param name="dist">The distance that the node will be built from the source node.</param>
        public NodeType getNodeType(FInt dist)
        {
            NodeType selType = null;
            foreach (NodeType type in NodeTypes)
            {
                if (type.BuildRangeMin <= dist)
                    selType = type;
                else
                    break;
            }

            return selType;
        }
Пример #20
0
 /// <summary>Determines how much higher or lower a point is than a line</summary>
 /// <param name="point">The point</param>
 /// <param name="lp1">The first point in the line</param>
 /// <param name="lp2">The second point in the line</param>
 /// <param name="slope">The slope of the line</param>
 /// <returns>How much higher or lower a point is than a line</returns>
 public static FInt LinePointDifference(VectorF point, VectorF lp1, VectorF lp2, FInt slope)
 {
     FInt a = point.Y - (lp1.Y + (point.X - lp1.X) * slope);
     return point.Y - (lp1.Y + (point.X - lp1.X) * slope);
 }
Пример #21
0
 public static FInt Acos(FInt F)
 {
     return Asin(F + F6435);
 }
Пример #22
0
        /// <summary>Runs the thread.</summary>
        private void run()
        {
            List<WorldEvent> evnts = new List<WorldEvent>();
            while (true)
            {
                evnts.Clear();
                Waiting = true;
                while (Waiting)
                {
                    if (Stop)
                        break;

                    if (SyncFinished)
                    {
                        lock (Events)
                        {
                            evnts.AddRange(Events);
                            Events.Clear();
                        }

                        lock (waiting)
                        {
                            lock (syncFinished)
                            {
                                waiting = false;
                                syncFinished = false;
                            }
                        }
                    }
                }

                if (Stop)
                    break;

                Grid.startNewUpdate(CurTime);

                #region Sync
                {
                    List<Node> newNodes = new List<Node>();
                    List<Segment> newSegs = new List<Segment>();
                    List<Node> updateNodes = new List<Node>();
                    List<List<Segment>> updateNodeSegs = new List<List<Segment>>();
                    SegmentSkel tempSeg = null;
                    NodeSkel tempNode = null;
                    foreach (WorldEvent evnt in evnts)
                    {
                        switch (evnt.WEvent)
                        {
                            // add segment
                            case WorldEvent.EventType.AddSeg:
                                if ((bool)evnt.Arguments[0]) // if owned by this player
                                {
                                    tempSeg = (Segment)evnt.Arguments[1];
                                    Segments.Add((Segment)tempSeg);
                                    newSegs.Add((Segment)tempSeg);
                                    Path.intersect(tempSeg.EndLoc[0], tempSeg.EndLoc[1], 1);
                                    tempSeg.Visible = true;
                                }
                                else
                                {
                                    tempSeg = new SegmentSkel();
                                    tempSeg.ID = (string)evnt.Arguments[1];
                                    tempSeg.EndLoc[0] = (VectorF)evnt.Arguments[2];
                                    tempSeg.State[0] = (SegmentSkel.SegState)evnt.Arguments[3];
                                    tempSeg.EndLoc[1] = (VectorF)evnt.Arguments[4];
                                    tempSeg.State[1] = (SegmentSkel.SegState)evnt.Arguments[5];
                                    lock (Owner.Fog) { tempSeg.Visible = Owner.Fog.isVisible(tempSeg); }
                                }

                                SegByID.Add(tempSeg.ID, tempSeg);
                                Grid.Line(tempSeg.EndLoc[0], tempSeg.EndLoc[1], tempSeg, gridAddSegment);
                                break;

                            // remove segment
                            case WorldEvent.EventType.RemSeg:
                                tempSeg = SegByID[(string)evnt.Arguments[0]];
                                if (tempSeg.Owner == Owner)
                                {
                                    Segments.Remove((Segment)tempSeg);
                                    Path.intersect(tempSeg.EndLoc[0], tempSeg.EndLoc[1], -1);
                                }
                                SegByID.Remove(tempSeg.ID);
                                Grid.Line(tempSeg.EndLoc[0], tempSeg.EndLoc[1], tempSeg, gridRemoveSegment);
                                break;

                            // change segment state
                            case WorldEvent.EventType.SegChangeState:
                                tempSeg = SegByID[(string)evnt.Arguments[0]];
                                Grid.Line(tempSeg.EndLoc[0], tempSeg.EndLoc[1], tempSeg, gridRemoveSegment);

                                if (tempSeg.Owner == Owner)
                                {
                                    Segment s = (Segment)tempSeg;
                                    FInt l0 = (FInt)evnt.Arguments[1];
                                    FInt l1 = (FInt)evnt.Arguments[3];

                                    bool reAdd = false;
                                    if (s.EndLength[0] != l0 || s.EndLength[1] != l1)
                                    {
                                        Path.intersect(s.EndLoc[0], s.EndLoc[1], -1);
                                        reAdd = true;
                                    }

                                    s.EndLength[0] = l0;
                                    s.State[0] = (SegmentSkel.SegState)evnt.Arguments[2];
                                    s.EndLength[1] = l1;
                                    s.State[1] = (SegmentSkel.SegState)evnt.Arguments[4];
                                    s.refreshEndLocs();

                                    if (reAdd)
                                        Path.intersect(s.EndLoc[0], s.EndLoc[1], 1);
                                }
                                else
                                {
                                    tempSeg.EndLoc[0] = (VectorF)evnt.Arguments[1];
                                    tempSeg.State[0] = (SegmentSkel.SegState)evnt.Arguments[2];
                                    tempSeg.EndLoc[1] = (VectorF)evnt.Arguments[3];
                                    tempSeg.State[1] = (SegmentSkel.SegState)evnt.Arguments[4];
                                    lock (Owner.Fog) { tempSeg.Visible = Owner.Fog.isVisible(tempSeg); }
                                }
                                Grid.Line(tempSeg.EndLoc[0], tempSeg.EndLoc[1], tempSeg, gridAddSegment);
                                break;

                            // add node
                            case WorldEvent.EventType.AddNode:
                                if ((bool)evnt.Arguments[0]) // if owned by this player
                                {
                                    tempNode = (Node)evnt.Arguments[1];
                                    tempNode.Visible = true;
                                    Nodes.Add((Node)tempNode);
                                    newNodes.Add((Node)tempNode);
                                }
                                else
                                {
                                    tempNode = new NodeSkel();
                                    tempNode.ID = (string)evnt.Arguments[1];
                                    tempNode.IsParent = (bool)evnt.Arguments[2];
                                    tempNode.Pos = (VectorF)evnt.Arguments[3];
                                    tempNode.Radius = (FInt)evnt.Arguments[4];
                                    lock (Owner.Fog) { tempNode.Visible = Owner.Fog.isVisible(tempNode); }
                                }

                                NodeByID.Add(tempNode.ID, tempNode);
                                Grid.Point(tempNode.Pos, tempNode, gridAddNode);

                                //if ((bool)evnt.Arguments[0] || tempNode.Active)
                                //	Path.intersect(tempNode.Pos, tempNode.Radius, 1);

                                if ((bool)evnt.Arguments[0] && tempNode.Active) // if owned by this player
                                    refreshVisibility(new VectorF(tempNode.X - tempNode.SightDistance, tempNode.Y - tempNode.SightDistance), new VectorF(tempNode.X + tempNode.SightDistance, tempNode.Y + tempNode.SightDistance));

                                break;

                            // change node state
                            case WorldEvent.EventType.NodeChangeState:
                                tempNode = NodeByID[(string)evnt.Arguments[0]];

                                if (tempNode.Owner == Owner) // if owned by this player
                                {
                                    Node realNode = (Node)tempNode;
                                    bool applyVisibility = !realNode.Active && (bool)evnt.Arguments[1];
                                    realNode.Active = (bool)evnt.Arguments[1];
                                    List<Segment> segs = (List<Segment>)evnt.Arguments[2];

                                    updateNodes.Add(realNode);
                                    updateNodeSegs.Add(segs);

                                    if (applyVisibility)
                                    {
                                        lock (Owner.Fog) { Owner.Fog.applyVisibility(realNode); }
                                        refreshVisibility(new VectorF(tempNode.X - tempNode.SightDistance, tempNode.Y - tempNode.SightDistance), new VectorF(tempNode.X + tempNode.SightDistance, tempNode.Y + tempNode.SightDistance));
                                    }
                                }
                                else
                                {
                                    /*if ((bool)evnt.Arguments[1] && !tempNode.Active)
                                        Path.intersect(tempNode.Pos, tempNode.Radius, 1);
                                    else if (!(bool)evnt.Arguments[1] && tempNode.Active)
                                        Path.intersect(tempNode.Pos, tempNode.Radius, -1);*/

                                    tempNode.Active = (bool)evnt.Arguments[1];
                                }
                                break;

                            // remove node
                            case WorldEvent.EventType.RemNode:
                                tempNode = NodeByID[(string)evnt.Arguments[0]];

                                // prepare to invalidate fog of war
                                VectorF upperLeft = VectorF.Zero;
                                VectorF lowerRight = VectorF.Zero;

                                if (tempNode.Active && tempNode.Owner == Owner)
                                {
                                    upperLeft = new VectorF(tempNode.X - tempNode.SightDistance, tempNode.Y - tempNode.SightDistance);
                                    lowerRight = new VectorF(tempNode.X + tempNode.SightDistance, tempNode.Y + tempNode.SightDistance);
                                }

                                if (tempNode.Owner == Owner)
                                    Nodes.Remove((Node)tempNode);
                                NodeByID.Remove(tempNode.ID);
                                Grid.Point(tempNode.Pos, tempNode, gridRemoveNode);

                                //if (tempNode.Owner == Owner || tempNode.Active)
                                //	Path.intersect(tempNode.Pos, tempNode.Radius, -1);

                                // invalidate fog of war
                                if (upperLeft != lowerRight)
                                {
                                    lock (Owner.Fog) { Owner.Fog.invalidate(upperLeft, lowerRight); }
                                    refreshVisibility(upperLeft, lowerRight);
                                }
                                break;
                            default:
                                throw new Exception("Unrecognized event: " + evnt.ToString());
                        }
                    }
                    evnts.Clear();

                    // link new nodes to their connected segments and parents
                    foreach (Node newNode in newNodes)
                    {
                        // segments
                        for (int i = 0; i < newNode.Segments.Length; i++)
                        {
                            if (newNode.Segments[i] != null)
                            {
                                SegmentSkel reassignSeg = null;
                                if (SegByID.TryGetValue(newNode.Segments[i].ID, out reassignSeg))
                                    newNode.Segments[i] = (Segment)reassignSeg;
            #if DEBUG
                                else
                                    throw new Exception("Segment id " + newNode.Segments[i].ID + " not found.");
            #endif
                            }
                        }

                        // parents
                        for (int i = 0; i < newNode.Parents.Count; i++)
                        {
                            NodeSkel reassignNode = null;
                            if (NodeByID.TryGetValue(newNode.Parents[i].ID, out reassignNode))
                                newNode.Parents[i] = (Node)reassignNode;
                        }
                    }

                    // link new segments to their connected nodes
                    foreach (Segment newSeg in newSegs)
                    {
                        for (int i = 0; i < 2; i++)
                        {
                            NodeSkel reassignNode = null;
                            if (NodeByID.TryGetValue(newSeg.Nodes[i].ID, out reassignNode))
                                newSeg.Nodes[i] = (Node)reassignNode;
                            else
                                newSeg.Nodes[i] = new Node(newSeg.Nodes[i]);
                        }
                    }

                    // link updated nodes to their connected segments
                    for (int i = 0; i < updateNodes.Count; i++)
                    {
                        Node node = updateNodes[i];
                        List<Segment> segs = updateNodeSegs[i];

                        updateNodes[i].NumSegments = 0;

                        for (int j = 0; j < segs.Count; j++)
                        {
                            if (segs[j] != null)
                                updateNodes[i].NumSegments++;

                            if (segs[j] == null && node.Segments[j] != null) // if removing a segment
                            {
                                node.Segments[j] = null;
                            }
                            else if (segs[j] != null && node.Segments[j] == null) // if adding a segment
                            {
                                node.Segments[j] = (Segment)SegByID[segs[j].ID];
                            }
                            else if (segs[j] != null && node.Segments[j] != null && segs[j].ID != node.Segments[j].ID) // if switching out a segment with another
                            {
                                node.Segments[j] = (Segment)SegByID[segs[j].ID];
                            }
                        }
                    }
                }
                #endregion Sync

                #region Update Destination

                if (destUpdateDue)
                {
                    // TODO: make this work

                    destUpdateDue = false;
                }

                #endregion Update Destination

                #region Decision-Making

                /*{ // Pattern AI
                Node top = null;
                Node bottom = null;
                Node right = null;
                Node left = null;

                foreach (Node n in Nodes)
                {
                    if (top == null || n.Pos.Y < top.Y)
                        top = n;

                    if (bottom == null || n.Pos.Y > bottom.Y)
                        bottom = n;

                    if (right == null || n.Pos.X > right.X)
                        right = n;

                    if (left == null || n.Pos.X < left.X)
                        left = n;
                }

                foreach (Node fromNode in Nodes)
                {
                    if (!fromNode.Active || fromNode.NumSegments > 1)
                        continue;

                    VectorF dest = VectorF.Zero;

                    if (fromNode.IsParent)
                    {
                        FInt x = (fromNode.Pos.X + fromNode.Segments[0].getOppNode(fromNode).Pos.X) / FInt.F2;
                        if (left == fromNode)
                            dest = new VectorF(x, fromNode.Pos.Y + (FInt)200);
                        else
                            dest = new VectorF(x, fromNode.Pos.Y - (FInt)200);
                    }
                    else
                    {
                        if (bottom == fromNode)
                            dest = new VectorF(right.Pos.X + (FInt)200, right.Pos.Y);
                        else if (top == fromNode)
                            dest = new VectorF(left.Pos.X - (FInt)200, left.Pos.Y);
                        else if (right == fromNode)
                            dest = new VectorF(top.Pos.X, top.Pos.Y - (FInt)200);
                        else // left
                            dest = new VectorF(bottom.Pos.X, bottom.Pos.Y + (FInt)200);
                    }

                    Actions.Add(new PlayerAction(Owner, PlayerAction.ActionType.BuildSeg, fromNode.ID, false, dest));
                }

                if (Actions.Count == 0)
                    for (int i = 0; i < 9999999; i++) { } // give the main loop a break
            }*/

                #endregion Decision-Making

                #region Decision-Making
                /*{ // Real thinking AI
                    Node bestNode = null;
                    PathNode bestPathNode = null;
                    FInt bestWorth = FInt.F0;
                    Node worstNode = null;
                    PathNode worstPathNode = null;
                    FInt worstWorth = FInt.F0;
                    bool stillBuilding = false;
                    FInt maxDist = (FInt)400;
                    foreach (Node fromNode in Nodes)
                    {
                        if (!fromNode.Active)
                            stillBuilding = true;

                        if (!fromNode.Active || fromNode.NumSegments == fromNode.Segments.Length)
                            continue;

                        VectorF fromPos = fromNode.Pos;

                        VectorF nSpacing = (VectorF)Path.NodeSpacing;
                        VectorF nde = new VectorF(fromPos.X - maxDist, fromPos.Y - maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int left = Math.Max(0, (int)nde.X);
                        int top = Math.Max(0, (int)nde.Y);
                        nde = new VectorF(fromPos.X + maxDist, fromPos.Y + maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int right = Math.Min(Path.NumCols - 1, (int)nde.X);
                        int bottom = Math.Min(Path.NumRows - 1, (int)nde.Y);
                        FInt[,] worth = new FInt[bottom - top + 1, right - left + 1];

                        nde = (Grid.Squares[0, 0].Nodes[0].Pos + Grid.Squares[0, 0].Nodes[1].Pos) / FInt.F2 / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        VectorF toPos = (VectorF)Path.Grid[(int)nde.Y, (int)nde.X].Position;
                        FInt totDist = VectorF.Distance(fromPos, toPos);

                        for (int row = top; row <= bottom; row++)
                        {
                            for (int col = left; col <= right; col++)
                            {
                                PathNode pn = Path.Grid[row, col];
                                VectorF pnPos = (VectorF)pn.Position;

                                // distance from source node
                                FInt srcDist = VectorF.Distance(fromPos, pnPos);
                                FInt srcDistWorth = FInt.F0;

                                if (srcDist > maxDist || srcDist < (FInt)100)
                                    srcDistWorth = FInt.F1 / FInt.F2;
                                else
                                    srcDistWorth = FInt.F1;

                                // distance from destination node
                                FInt destDist = VectorF.Distance(toPos, pnPos);
                                FInt destDistWorth = FInt.F1 - (destDist / (maxDist * FInt.F2));

                                // collisions
                                List<NodeSkel> ignoreNode = new List<NodeSkel>(1) { fromNode };
                                List<SegmentSkel> ignoreSeg = new List<SegmentSkel>(fromNode.NumSegments);
                                foreach (Segment seg in fromNode.Segments)
                                {
                                    if (seg != null)
                                        ignoreSeg.Add(seg);
                                }

                                FInt collWorth = FInt.F0;
                                List<SegmentSkel> collSeg;
                                List<NodeSkel> collNode;
                                List<GeoSkel> collGeo;
                                if (Collision.segCollision(fromPos, pnPos, ignoreSeg, ignoreNode, out collSeg, out collNode, out collGeo, true, Owner))
                                {
                                    if (collGeo.Count > 0)
                                    {
                                        collWorth = FInt.F0;
                                    }
                                    else if (collNode.Count > 0)
                                    {
                                        collWorth = FInt.F0;
                                    }
                                    else
                                    {
                                        SegmentSkel closestSeg = null;
                                        VectorF closestInt = VectorF.Zero;
                                        FInt closestDist = FInt.F0;

                                        for (int i = 0; i < collSeg.Count; i++)
                                        {
                                            VectorF nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);

                                            if (collSeg[i].Owner == Owner)
                                            {
                                                VectorF end0 = (collSeg[i].State[1] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[0]
                                                    : ((Segment)collSeg[i]).Nodes[0].Pos;

                                                VectorF end1 = (collSeg[i].State[0] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[1]
                                                    : ((Segment)collSeg[i]).Nodes[1].Pos;

                                                nextInt = Calc.LineIntersect(fromPos, pnPos, end0, end1);
                                            }
                                            else
                                            {
                                                nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);
                                            }

                                            FInt nextDist = VectorF.Distance(fromPos, nextInt);

                                            if (closestSeg == null || nextDist < closestDist)
                                            {
                                                closestSeg = collSeg[i];
                                                closestInt = nextInt;
                                                closestDist = nextDist;
                                            }
                                        }

                                        if (closestSeg.Owner == Owner)
                                            collWorth = FInt.F0;
                                        else
                                            collWorth = FInt.F1;
                                    }
                                }
                                else
                                {
                                    NodeType nType = Owner.InWorld.getNodeType(srcDist);

                                    if (pnPos.X - nType.Radius < 0
                                        || pnPos.Y - nType.Radius < 0
                                        || pnPos.X + nType.Radius >= Owner.InWorld.Width
                                        || pnPos.Y + nType.Radius >= Owner.InWorld.Height
                                        || Collision.nodeCollision(pnPos, nType.Radius, new List<SegmentSkel>(0), new List<NodeSkel>(0), true, Owner)
                                        || Collision.nodeCollNodeSpacing(pnPos, nType.Radius, nType.Spacing, Owner, new List<NodeSkel>(0), true))
                                    {
                                        collWorth = FInt.F0;
                                    }
                                    else
                                        collWorth = FInt.F1 / FInt.F2;
                                }

                                // calculate worth
                                worth[row - top, col - left] = (collWorth * FInt.F5) + (srcDistWorth * FInt.F2) + destDistWorth;

                                if (worth[row - top, col - left] > bestWorth || (worth[row - top, col - left] == bestWorth && new Random().Next(2) == 1))
                                {
                                    bestNode = fromNode;
                                    bestPathNode = pn;
                                    bestWorth = worth[row - top, col - left];
                                }
                                else if (fromNode.NumSegments == 1 && worth[row - top, col - left] < worstWorth || (worth[row - top, col - left] == worstWorth && new Random().Next(2) == 1))
                                {
                                    worstNode = fromNode;
                                    worstPathNode = pn;
                                    worstWorth = worth[row - top, col - left];
                                }
                            }
                        }
                    }

                    PlayerAction action = null;

                    if (bestPathNode != null && bestNode != null && (!stillBuilding || bestWorth > (FInt)3.5)) // if worth isn't high enough, don't do anything
                        action = new PlayerAction(Owner, PlayerAction.ActionType.BuildSeg, bestNode.ID, false, (VectorF)bestPathNode.Position);
                    else if (worstPathNode != null && worstNode != null)
                        action = new PlayerAction(Owner, PlayerAction.ActionType.DestroyNode, worstNode.ID);

                    if (action != null)
                    {
                        lock (Actions)
                            Actions.Add(action);
                    }

                }*/
                #endregion Decision-Making

                #region Decision-Making
                if (false)
                {
                    VectorF nSpacing = (VectorF)Path.NodeSpacing;

                    VectorF dest = (Grid.Squares[0, 0].Nodes[0].Pos + Grid.Squares[0, 0].Nodes[1].Pos) / FInt.F2 / nSpacing;
                    PathNode destNode = Path.Grid[(int)dest.Y, (int)dest.X];
                    dest = (VectorF)destNode.Position;
                    Node uselessNode = null;
                    List<NodeDistPath> openNodes = new List<NodeDistPath>();

                    // collect list of nodes with an open branch
                    foreach (Node n in Nodes)
                    {
                        if (n.Active && n.NumSegments < n.Segments.Length)
                            openNodes.Add(new NodeDistPath(n, VectorF.Distance(n.Pos, dest), null));
                    }

                    //
                    // FIND CLOSEST NODE TO DESTINATION
                    //

                    // sort nodes by distance from destination
                    NodeDistPath swap;
                    for (int i = 1, j; i < openNodes.Count; i++)
                    {
                        for (j = i; j > 0 && openNodes[j] < openNodes[j - 1]; j--)
                        {
                            swap = openNodes[j];
                            openNodes[j] = openNodes[j - 1];
                            openNodes[j - 1] = swap;
                        }
                    }

                    // find the node with the shortest path to the destination
                    while (openNodes.Count > 0 && openNodes[0].Path == null)
                    {
                        // get a starting path node
                        PathNode srcNode = Path.Grid[(int)((double)openNodes[0].Node.Pos.Y / Path.NodeSpacing.Y), (int)((double)openNodes[0].Node.Pos.X / Path.NodeSpacing.X)];
                        while (srcNode.isOrphaned())
                        {
                            srcNode = Path.Nodes[srcNode.Index - Path.NumCols];
                        }

                        // get shortest path
                        openNodes[0].Path = Path.gridToList(Path.search(srcNode, destNode), srcNode, destNode);

                        // if path doesn't exist
                        if (openNodes[0].Path == null)
                        {
                            openNodes.RemoveAt(0);
                            continue;
                        }

                        double dist = 0d;
                        foreach (PathEdge edge in openNodes[0].Path)
                        {
                            dist += edge.Distance;
                        }
                        openNodes[0].Dist = (FInt)dist;

                        // update order in list
                        for (int i = 0; i < openNodes.Count - 1 && openNodes[i] > openNodes[i + 1]; i++)
                        {
                            swap = openNodes[i];
                            openNodes[i] = openNodes[i + 1];
                            openNodes[i + 1] = swap;
                        }
                    }

                    if (openNodes.Count > 0)
                    {

                        // find furthest reachable path node
                        FInt maxDist = (FInt)400; // TODO: get rid of magic number (400)
                        int magnetEdge = -1;
                        for (int i = openNodes[0].Path.Count - 1; i >= 0; i--)
                        {
                            if (VectorF.Distance(openNodes[0].Node.Pos, (VectorF)Path.Nodes[openNodes[0].Path[i].NodeDest].Position) < maxDist)
                            {
                                magnetEdge = i;
                                break;
                            }
                        }

                        // find furthest node with no collisions
                        List<NodeSkel> ignoreNode = new List<NodeSkel>(1) { openNodes[0].Node };
                        List<SegmentSkel> ignoreSeg = new List<SegmentSkel>(openNodes[0].Node.NumSegments);
                        foreach (Segment seg in openNodes[0].Node.Segments)
                        {
                            if (seg != null)
                                ignoreSeg.Add(seg);
                        }
                        List<SegmentSkel> collSeg;
                        List<NodeSkel> collNode;
                        List<GeoSkel> collGeo;
                        VectorF magnetPoint = VectorF.Zero;

                        for (int i = magnetEdge; i >= 0; i--)
                        {
                            bool collision = false;
                            if (Collision.segCollision(openNodes[0].Node.Pos, (VectorF)Path.Nodes[openNodes[0].Path[i].NodeDest].Position, ignoreSeg, ignoreNode, out collSeg, out collNode, out collGeo, true, Owner))
                            {
                                if (collNode.Count > 0 || collGeo.Count > 0)
                                {
                                    collision = true;
                                }
                                else
                                {
                                    foreach (SegmentSkel s in collSeg)
                                    {
                                        if (s.Owner == Owner)
                                        {
                                            collision = true;
                                            break;
                                        }
                                    }
                                }
                            }

                            if (!collision)
                            {
                                magnetPoint = (VectorF)Path.Nodes[openNodes[0].Path[i].NodeDest].Position;
                                break;
                            }
                        }

                        // find best path node towards destination

                        VectorF nde = new VectorF(openNodes[0].Node.X - maxDist, openNodes[0].Node.Y - maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int left = Math.Max(0, (int)nde.X);
                        int top = Math.Max(0, (int)nde.Y);
                        nde = new VectorF(openNodes[0].Node.X + maxDist, openNodes[0].Node.Y + maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int right = Math.Min(Path.NumCols - 1, (int)nde.X);
                        int bottom = Math.Min(Path.NumRows - 1, (int)nde.Y);

                        Node bestNode = null;
                        PathNode bestPNode = null;
                        FInt bestWorth = FInt.F0;
                        for (int row = top; row <= bottom; row++)
                        {
                            for (int col = left; col <= right; col++)
                            {
                                PathNode pn = Path.Grid[row, col];
                                VectorF pnPos = (VectorF)pn.Position;

                                FInt collWorth = FInt.F0;

                                if (Collision.segCollision(openNodes[0].Node.Pos, pnPos, ignoreSeg, ignoreNode, out collSeg, out collNode, out collGeo, true, Owner))
                                {
                                    if (collGeo.Count > 0 || collNode.Count > 0)
                                    {
                                        collWorth = FInt.FN1;
                                    }
                                    else
                                    {
                                        SegmentSkel closestSeg = null;
                                        VectorF closestInt = VectorF.Zero;
                                        FInt closestDist = FInt.F0;

                                        for (int i = 0; i < collSeg.Count; i++)
                                        {
                                            VectorF nextInt = Calc.LineIntersect(openNodes[0].Node.Pos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);

                                            if (collSeg[i].Owner == Owner)
                                            {
                                                VectorF end0 = (collSeg[i].State[1] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[0]
                                                    : ((Segment)collSeg[i]).Nodes[0].Pos;

                                                VectorF end1 = (collSeg[i].State[0] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[1]
                                                    : ((Segment)collSeg[i]).Nodes[1].Pos;

                                                nextInt = Calc.LineIntersect(openNodes[0].Node.Pos, pnPos, end0, end1);
                                            }
                                            else
                                            {
                                                nextInt = Calc.LineIntersect(openNodes[0].Node.Pos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);
                                            }

                                            FInt nextDist = VectorF.Distance(openNodes[0].Node.Pos, nextInt);

                                            if (closestSeg == null || nextDist < closestDist)
                                            {
                                                closestSeg = collSeg[i];
                                                closestInt = nextInt;
                                                closestDist = nextDist;
                                            }
                                        }

                                        if (closestSeg.Owner == Owner)
                                            collWorth = FInt.FN1;
                                        else
                                            collWorth = FInt.F1;
                                    }
                                }
                                else
                                {
                                    NodeType nType = Owner.InWorld.getNodeType(VectorF.Distance(openNodes[0].Node.Pos, pnPos));

                                    if (pnPos.X - nType.Radius < 0
                                        || pnPos.Y - nType.Radius < 0
                                        || pnPos.X + nType.Radius >= Owner.InWorld.Width
                                        || pnPos.Y + nType.Radius >= Owner.InWorld.Height
                                        || Collision.nodeCollision(pnPos, nType.Radius, new List<SegmentSkel>(0), new List<NodeSkel>(0), true, Owner)
                                        || Collision.nodeCollNodeSpacing(pnPos, nType.Radius, nType.Spacing, Owner, new List<NodeSkel>(0), true))
                                    {
                                        collWorth = FInt.FN1;
                                    }
                                }

                                if (collWorth != FInt.FN1)
                                {
                                    // distance from destination node
                                    FInt destDist = VectorF.Distance(magnetPoint, pnPos);
                                    FInt worth = maxDist - destDist + collWorth;

                                    if (bestPNode == null || worth > bestWorth || (worth == bestWorth && new Random().Next(2) == 1))
                                    {
                                        bestPNode = pn;
                                        bestWorth = worth;
                                    }
                                }
                            }
                        }

                        if (bestPNode != null)
                            bestNode = openNodes[0].Node;

                        //
                        // FIND MOST USELESS NODE
                        //

                        for (int i = openNodes.Count - 1; i >= 0; i--)
                        {
                            if (!openNodes[i].Node.IsParent && openNodes[i].Node.NumSegments == 1)
                            {
                                uselessNode = openNodes[i].Node;
                                break;
                            }
                        }

                        //
                        // FIND INTERSECTIONS
                        //

                        foreach (NodeDistPath fromNode in openNodes)
                        {
                            VectorF fromPos = fromNode.Node.Pos;

                            nde = new VectorF(fromPos.X - maxDist, fromPos.Y - maxDist) / nSpacing;
                            nde.X = (FInt)Math.Round((double)nde.X);
                            nde.Y = (FInt)Math.Round((double)nde.Y);
                            left = Math.Max(0, (int)nde.X);
                            top = Math.Max(0, (int)nde.Y);
                            nde = new VectorF(fromPos.X + maxDist, fromPos.Y + maxDist) / nSpacing;
                            nde.X = (FInt)Math.Round((double)nde.X);
                            nde.Y = (FInt)Math.Round((double)nde.Y);
                            right = Math.Min(Path.NumCols - 1, (int)nde.X);
                            bottom = Math.Min(Path.NumRows - 1, (int)nde.Y);

                            nde = (Grid.Squares[0, 0].Nodes[0].Pos + Grid.Squares[0, 0].Nodes[1].Pos) / FInt.F2 / nSpacing;
                            nde.X = (FInt)Math.Round((double)nde.X);
                            nde.Y = (FInt)Math.Round((double)nde.Y);

                            for (int row = top; row <= bottom; row++)
                            {
                                for (int col = left; col <= right; col++)
                                {
                                    PathNode pn = Path.Grid[row, col];
                                    VectorF pnPos = (VectorF)pn.Position;

                                    // distance from source node
                                    FInt srcDist = VectorF.Distance(fromPos, pnPos);

                                    // collisions
                                    ignoreNode = new List<NodeSkel>(1) { fromNode.Node };
                                    ignoreSeg = new List<SegmentSkel>(fromNode.Node.NumSegments);
                                    foreach (Segment seg in fromNode.Node.Segments)
                                    {
                                        if (seg != null)
                                            ignoreSeg.Add(seg);
                                    }

                                    FInt collWorth = FInt.F0;
                                    if (Collision.segCollision(fromPos, pnPos, ignoreSeg, ignoreNode, out collSeg, out collNode, out collGeo, true, Owner) && collGeo.Count == 0 && collNode.Count == 0)
                                    {
                                        SegmentSkel closestSeg = null;
                                        VectorF closestInt = VectorF.Zero;
                                        FInt closestDist = FInt.F0;

                                        for (int i = 0; i < collSeg.Count; i++)
                                        {
                                            VectorF nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);

                                            if (collSeg[i].Owner == Owner)
                                            {
                                                VectorF end0 = (collSeg[i].State[1] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[0]
                                                    : ((Segment)collSeg[i]).Nodes[0].Pos;

                                                VectorF end1 = (collSeg[i].State[0] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[1]
                                                    : ((Segment)collSeg[i]).Nodes[1].Pos;

                                                nextInt = Calc.LineIntersect(fromPos, pnPos, end0, end1);
                                            }
                                            else
                                            {
                                                nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);
                                            }

                                            FInt nextDist = VectorF.Distance(fromPos, nextInt);

                                            if (closestSeg == null || nextDist < closestDist)
                                            {
                                                closestSeg = collSeg[i];
                                                closestInt = nextInt;
                                                closestDist = nextDist;
                                            }
                                        }

                                        if (closestSeg.Owner == Owner)
                                            collWorth = FInt.F0;
                                        else
                                            collWorth = FInt.F1;

                                        // calculate worth

                                        FInt worth = collWorth * (maxDist - closestDist) * 2;

                                        if (bestPNode == null || worth > bestWorth || (worth == bestWorth && new Random().Next(2) == 1))
                                        {
                                            bestNode = fromNode.Node;
                                            bestPNode = pn;
                                            bestWorth = worth;
                                        }
                                    }
                                }
                            }
                        }

                        //
                        // MAKE DECISION
                        //

                        PlayerAction action = null;

                        if (bestPNode != null && bestNode != null && (bestWorth > (FInt)3.5)) // if worth isn't high enough, don't do anything
                            action = new PlayerAction(Owner, PlayerAction.ActionType.BuildSeg, bestNode.ID, false, (VectorF)bestPNode.Position);
                        else if (uselessNode != null)
                            action = new PlayerAction(Owner, PlayerAction.ActionType.DestroyNode, uselessNode.ID);

                        if (action != null)
                        {
                            lock (Actions)
                                Actions.Add(action);
                        }
                    }
                }

                #endregion Decision-Making

                #region Decision-Making

                if (false)
                {
                    // Real thinking AI
                    Node bestNode = null;
                    PathNode bestPathNode = null;
                    FInt bestWorth = FInt.F0;
                    Node worstNode = null;
                    PathNode worstPathNode = null;
                    FInt worstWorth = FInt.F0;
                    bool stillBuilding = false;
                    FInt maxDist = (FInt)400;
                    foreach (Node fromNode in Nodes)
                    {
                        if (!fromNode.Active)
                            stillBuilding = true;

                        if (!fromNode.Active || fromNode.NumSegments == fromNode.Segments.Length)
                            continue;

                        VectorF fromPos = fromNode.Pos;

                        VectorF nSpacing = (VectorF)Path.NodeSpacing;
                        VectorF nde = new VectorF(fromPos.X - maxDist, fromPos.Y - maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int left = Math.Max(0, (int)nde.X);
                        int top = Math.Max(0, (int)nde.Y);
                        nde = new VectorF(fromPos.X + maxDist, fromPos.Y + maxDist) / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        int right = Math.Min(Path.NumCols - 1, (int)nde.X);
                        int bottom = Math.Min(Path.NumRows - 1, (int)nde.Y);
                        FInt[,] worth = new FInt[bottom - top + 1, right - left + 1];

                        nde = (Grid.Squares[0, 0].Nodes[0].Pos + Grid.Squares[0, 0].Nodes[1].Pos) / FInt.F2 / nSpacing;
                        nde.X = (FInt)Math.Round((double)nde.X);
                        nde.Y = (FInt)Math.Round((double)nde.Y);
                        VectorF toPos = (VectorF)Path.Grid[(int)nde.Y, (int)nde.X].Position;
                        FInt totDist = VectorF.Distance(fromPos, toPos);

                        for (int row = top; row <= bottom; row++)
                        {
                            for (int col = left; col <= right; col++)
                            {
                                PathNode pn = Path.Grid[row, col];
                                VectorF pnPos = (VectorF)pn.Position;

                                // distance from source node
                                FInt srcDist = VectorF.Distance(fromPos, pnPos);
                                FInt srcDistWorth = FInt.F0;

                                if (srcDist > maxDist || srcDist < (FInt)100)
                                    srcDistWorth = FInt.F1 / FInt.F2;
                                else
                                    srcDistWorth = FInt.F1;

                                // distance from destination node
                                FInt destDist = VectorF.Distance(toPos, pnPos);
                                FInt destDistWorth = FInt.F1 - (destDist / (maxDist * FInt.F2));

                                // collisions
                                List<NodeSkel> ignoreNode = new List<NodeSkel>(1) { fromNode };
                                List<SegmentSkel> ignoreSeg = new List<SegmentSkel>(fromNode.NumSegments);
                                foreach (Segment seg in fromNode.Segments)
                                {
                                    if (seg != null)
                                        ignoreSeg.Add(seg);
                                }

                                FInt collWorth = FInt.F0;
                                List<SegmentSkel> collSeg;
                                List<NodeSkel> collNode;
                                List<GeoSkel> collGeo;
                                if (Collision.segCollision(fromPos, pnPos, ignoreSeg, ignoreNode, out collSeg, out collNode, out collGeo, true, Owner))
                                {
                                    if (collGeo.Count > 0 || collNode.Count > 0)
                                    {
                                        collWorth = FInt.F0;
                                    }
                                    else
                                    {
                                        SegmentSkel closestSeg = null;
                                        VectorF closestInt = VectorF.Zero;
                                        FInt closestDist = FInt.F0;

                                        for (int i = 0; i < collSeg.Count; i++)
                                        {
                                            VectorF nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);

                                            if (collSeg[i].Owner == Owner)
                                            {
                                                VectorF end0 = (collSeg[i].State[1] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[0]
                                                    : ((Segment)collSeg[i]).Nodes[0].Pos;

                                                VectorF end1 = (collSeg[i].State[0] == SegmentSkel.SegState.Retracting)
                                                    ? collSeg[i].EndLoc[1]
                                                    : ((Segment)collSeg[i]).Nodes[1].Pos;

                                                nextInt = Calc.LineIntersect(fromPos, pnPos, end0, end1);
                                            }
                                            else
                                            {
                                                nextInt = Calc.LineIntersect(fromPos, pnPos, collSeg[i].EndLoc[0], collSeg[i].EndLoc[1]);
                                            }

                                            FInt nextDist = VectorF.Distance(fromPos, nextInt);

                                            if (closestSeg == null || nextDist < closestDist)
                                            {
                                                closestSeg = collSeg[i];
                                                closestInt = nextInt;
                                                closestDist = nextDist;
                                            }
                                        }

                                        if (closestSeg.Owner == Owner)
                                            collWorth = FInt.F0;
                                        else
                                            collWorth = FInt.F1;
                                    }
                                }
                                else
                                {
                                    NodeType nType = Owner.InWorld.getNodeType(srcDist);

                                    if (pnPos.X - nType.Radius < 0
                                        || pnPos.Y - nType.Radius < 0
                                        || pnPos.X + nType.Radius >= Owner.InWorld.Width
                                        || pnPos.Y + nType.Radius >= Owner.InWorld.Height
                                        || Collision.nodeCollision(pnPos, nType.Radius, new List<SegmentSkel>(0), new List<NodeSkel>(0), true, Owner)
                                        || Collision.nodeCollNodeSpacing(pnPos, nType.Radius, nType.Spacing, Owner, new List<NodeSkel>(0), true))
                                    {
                                        collWorth = FInt.F0;
                                    }
                                    else
                                        collWorth = FInt.F1 / FInt.F2;
                                }

                                // calculate worth
                                worth[row - top, col - left] = (collWorth * FInt.F5) + (srcDistWorth * FInt.F2) + destDistWorth;

                                if (worth[row - top, col - left] > bestWorth || (worth[row - top, col - left] == bestWorth && new Random().Next(2) == 1))
                                {
                                    bestNode = fromNode;
                                    bestPathNode = pn;
                                    bestWorth = worth[row - top, col - left];
                                }
                                else if (fromNode.NumSegments == 1 && worth[row - top, col - left] < worstWorth || (worth[row - top, col - left] == worstWorth && new Random().Next(2) == 1))
                                {
                                    worstNode = fromNode;
                                    worstPathNode = pn;
                                    worstWorth = worth[row - top, col - left];
                                }
                            }
                        }
                    }

                    PlayerAction action = null;

                    if (bestPathNode != null && bestNode != null && (!stillBuilding || bestWorth > (FInt)3.5)) // if worth isn't high enough, don't do anything
                        action = new PlayerAction(Owner, PlayerAction.ActionType.BuildSeg, bestNode.ID, false, (VectorF)bestPathNode.Position);
                    else if (worstPathNode != null && worstNode != null)
                        action = new PlayerAction(Owner, PlayerAction.ActionType.DestroyNode, worstNode.ID);

                    if (action != null)
                    {
                        lock (Actions)
                            Actions.Add(action);
                    }

                }
                #endregion Decision-Making
            }

            Waiting = false;
        }
Пример #23
0
 public static FInt Atan(FInt F)
 {
     return Asin(F / Sqrt(FInt.OneF + (F * F)));
 }
Пример #24
0
 /// <summary>Rounds the number to the nearest integer.</summary>
 /// <param name="num">The number to round.</param>
 /// <returns>The number rounded to the nearest integer.</returns>
 public static FInt Round(FInt num)
 {
     return (FInt)(int)(num + (FInt).5);
 }
Пример #25
0
        private static FInt sin_lookup(FInt i, FInt j)
        {
            FInt rawValue = new FInt(SIN_TABLE[i.RawValue], false);

            if (j > 0 && j < F10 && i < new FInt(90, false))
                return rawValue +
                    ((new FInt(SIN_TABLE[i.RawValue + 1], false) - rawValue) /
                    F10) * j;
            else
                return rawValue;
        }
Пример #26
0
 public static FInt Cos(FInt i)
 {
     return Sin(i + F6435);
 }
Пример #27
0
        /// <summary>Search the specified grid square for a segment owned by the specified player that overlaps the specified point.</summary>
        /// <param name="sqr">The grid square to search.</param>
        /// <param name="array">An array containing the following values: the point to search, the owner of the segment (null if any), and the segment, if found.</param>
        /// <param name="time">The current game time.</param>
        /// <param name="opID">The current operation id.</param>
        private void gridSegmentAtPoint(GridSqr sqr, object array, TimeSpan time, int opID)
        {
            VectorF point = (VectorF)((object[])array)[0];
            Player owner = (Player)((object[])array)[1];

            FInt top = new FInt();
            FInt left = new FInt();
            FInt right = new FInt();
            FInt bottom = new FInt();

            // TODO: specify threshold
            FInt thresh = (FInt)10;

            foreach (Segment seg in sqr.Segments)
            {
                if (seg.LastCheck != time || seg.LastCheckNum != opID)
                {
                    seg.LastCheck = time;
                    seg.LastCheckNum = opID;

                    // get bounding box
                    if (seg.EndLoc[0].X < seg.EndLoc[1].X)
                    {
                        left = seg.EndLoc[0].X;
                        right = seg.EndLoc[1].X;
                    }
                    else
                    {
                        left = seg.EndLoc[1].X;
                        right = seg.EndLoc[0].X;
                    }

                    if (seg.EndLoc[0].Y < seg.EndLoc[1].Y)
                    {
                        top = seg.EndLoc[0].Y;
                        bottom = seg.EndLoc[1].Y;
                    }
                    else
                    {
                        top = seg.EndLoc[1].Y;
                        bottom = seg.EndLoc[0].Y;
                    }

                    // test segment
                    if ((seg.Owner == owner || owner == null)
                        && point.X >= left - thresh
                        && point.X <= right + thresh
                        && point.Y >= top - thresh
                        && point.Y <= bottom + thresh
                        && seg.overlapsPoint(point))
                    {
                        ((object[])array)[2] = seg;
                        Grid.CancelOperation = true;
                        break;
                    }
                }
            }
        }
Пример #28
0
 /// <summary>Determines the approximate distance between a line and a point at their closest point</summary>
 /// <param name="point">The point</param>
 /// <param name="lp1">The first point in the line</param>
 /// <param name="lp2">The second point in the line</param>
 /// <param name="length">The length of the line.  Provide so that the method doesn't have to calculate it again.</param>
 /// <returns>The approximate distance between a line and a point at their closest point</returns>
 public static FInt LinePointDistApprox(VectorF point, VectorF lp1, VectorF lp2, FInt length)
 {
     return length == FInt.F0 ? VectorF.DistanceApprox(point, lp1) : VectorF.DistanceApprox(lp1 + ((length - VectorF.DistanceApprox(lp2, point) + VectorF.DistanceApprox(lp1, point)) / FInt.F2 / length) * (lp2 - lp1), point);
 }
Пример #29
0
        /// <summary>Called when btnEditorNodeApply is clicked.</summary>
        private void btnEditorNodeApply_MouseLeftUp(object sender, EventArgs e)
        {
            if (string.IsNullOrWhiteSpace(txtEditorNodeID.Text))
            {
                showMsg("The \"ID\" value cannot be blank.");
                return;
            }

            int numSegs = int.Parse(txtEditorNodeNumSegs.Text);
            if (numSegs < selectedNode.NumSegments)
            {
                showMsg("The \"NumSeg\" value must be greater than or equal to the number of segments already attached to the selected node.");
                return;
            }
            if (!string.IsNullOrWhiteSpace(txtEditorNodeOwnsHotspot.Text) && !world.HotspotByID.ContainsKey(txtEditorNodeOwnsHotspot.Text))
            {
                showMsg("The \"OwnsHotspot\" value must either be empty or be equal to an existing hotspot's ID.");
                return;
            }

            // make sure the node ID is not a duplicate
            foreach (Node n in world.Nodes)
            {
                if (n.ID == txtEditorNodeID.Text && n != selectedNode)
                {
                    showMsg("A node with that ID already exists.");
                    return;
                }
            }

            selectedNode.Owner = (cmbEditorNodeOwner.SelectedIndex == 0)
                ? null
                : world.Players[cmbEditorNodeOwner.SelectedIndex - 1];

            if (selectedNode.NType != world.NodeTypes[cmbEditorNodeType.SelectedIndex])
                selectedNode.setNodeType(world.NodeTypes[cmbEditorNodeType.SelectedIndex]);

            selectedNode.IsParent = btnEditorNodeIsParent.Pressed;
            selectedNode.Radius = (FInt)double.Parse(txtEditorNodeRadius.Text);
            selectedNode.Spacing = (FInt)double.Parse(txtEditorNodeSpacing.Text);
            selectedNode.GenSpacing = (FInt)double.Parse(txtEditorNodeGenSpacing.Text);
            selectedNode.GenCountDown = (FInt)double.Parse(txtEditorNodeGenCountDown.Text);
            selectedNode.SightDistance = (FInt)double.Parse(txtEditorNodeSightDist.Text);
            selectedNode.Active = btnEditorNodeActive.Pressed;

            if (!string.IsNullOrWhiteSpace(txtEditorNodeOwnsHotspot.Text))
                selectedNode.OwnsHotspot = world.HotspotByID[txtEditorNodeOwnsHotspot.Text];

            if (numSegs != selectedNode.Segments.Length)
            {
                Segment[] segs = new Segment[numSegs];
                int[] segNumPpl = new int[numSegs];
                FInt[] segCap = new FInt[numSegs];

                int index = 0;
                for (int i = 0; i < selectedNode.Segments.Length; i++)
                {
                    if (selectedNode.Segments[i] != null)
                    {
                        segs[index] = selectedNode.Segments[i];
                        segNumPpl[index] = selectedNode.SegNumPeople[i];
                        segCap[index] = selectedNode.SegCapacity[i];

                        index++;
                    }
                }
            }

            // move node
            if (selectedNode.X.ToString() != txtEditorNodeX.Text
                || selectedNode.Y.ToString() != txtEditorNodeY.Text)
            {
                VectorF moveTo = new VectorF((FInt)double.Parse(txtEditorNodeX.Text), (FInt)double.Parse(txtEditorNodeY.Text));
                moveNode(selectedNode, moveTo);
            }

            // apply node ID
            if (selectedNode.ID != txtEditorNodeID.Text)
            {
                selectedNode.ID = txtEditorNodeID.Text;
                world.refreshNextGenIDs();
            }
        }
Пример #30
0
 public static FInt Max(FInt F1, FInt F2)
 {
     if (F1.RawValue > F2.RawValue)
         return F1;
     return F2;
 }