/// <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; }
public static FInt Abs(FInt F) { if (F < FInt.F0) return F.Inverse; else return F; }
/// <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; }
/// <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; }
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; }
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; }
/// <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; }
/// <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; }
private static FInt mul(FInt F1, FInt F2) { return F1 * F2; }
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); }
public static FInt Tan(FInt i) { return Sin(i) / Cos(i); }
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; }
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; }
/// <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)); }
/// <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; }
/// <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); } } } }
public static FInt Min(FInt F1, FInt F2) { if (F1.RawValue < F2.RawValue) return F1; return F2; }
/// <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); } } }
/// <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; }
/// <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); }
public static FInt Acos(FInt F) { return Asin(F + F6435); }
/// <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; }
public static FInt Atan(FInt F) { return Asin(F / Sqrt(FInt.OneF + (F * F))); }
/// <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); }
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; }
public static FInt Cos(FInt i) { return Sin(i + F6435); }
/// <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; } } } }
/// <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); }
/// <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(); } }
public static FInt Max(FInt F1, FInt F2) { if (F1.RawValue > F2.RawValue) return F1; return F2; }