public LineIntercept(LineSegment segment, Vector2 point) { this.segment = segment; this.point = point; }
public override bool Shoot(Player player, ref Vector2 position, ref float speedX, ref float speedY, ref int type, ref int damage, ref float knockBack) { //TODO: rewrite this... again... /*Vector2 dir = new Vector2(speedX, speedY).SafeNormalize(new Vector2(0, 1)); * List<Vector2> endPoints = new List<Vector2>(); * int maxIterations = 600; * int maxDistanceBetweenSpawns = 16; * int maxTotalDistance = 1200; * float currentDistance = 0; * int distancePerIteration = 8; * Vector2 currentPosition = position * 1; * endPoints.Add(position); * for(int i=0;i<=maxIterations && currentDistance < maxTotalDistance - 1; i++) { * Point currentTilePosition = currentPosition.ToTileCoordinates(); * Point nextTilePosition = (currentPosition + (dir * distancePerIteration)).ToTileCoordinates(); * if(!WorldGen.InWorld(nextTilePosition.X, nextTilePosition.Y, 10)) * break; * Tile nextTile = Main.tile[nextTilePosition] * } * endPoints.Add(currentPosition); * * return false; * }*/ Vector2 dir = new Vector2(speedX, speedY).SafeNormalize(new Vector2(0, 1)); int maxDistancePerIteration = 16; int maxIterations = 600; int maxDistanceBetweenSpawns = 16; int maxTotalDistance = 1200; float currentDistance = 0; List <Vector2> endPoints = new List <Vector2>(); endPoints.Add(position); Point currentTilePos = position.ToTileCoordinates(); for (int i = 0; i <= maxIterations && currentDistance < maxTotalDistance - 1; i++) { Vector2 previousDir = dir; float distanceThisIteration = (currentDistance + maxDistancePerIteration <= maxTotalDistance ? maxDistancePerIteration : maxTotalDistance - currentDistance); Vector2 nextPos = position + dir * distanceThisIteration; LineSegment motion = new LineSegment(position, nextPos); GeneralDirection genDir; if (dir.X >= 0) { if (dir.Y <= 0) { genDir = GeneralDirection.UpRight; } else { genDir = GeneralDirection.DownRight; } } else { if (dir.Y <= 0) { genDir = GeneralDirection.UpLeft; } else { genDir = GeneralDirection.DownLeft; } } bool hitTile = false; Tile currentTile = Main.tile[currentTilePos.X, currentTilePos.Y]; Tile tileDown = Main.tile[currentTilePos.X, currentTilePos.Y + 1]; while (true) { float xCoord = 0; switch (genDir) { case GeneralDirection.UpRight: case GeneralDirection.DownRight: xCoord = currentTilePos.X * 16f + 16f; break; case GeneralDirection.UpLeft: case GeneralDirection.DownLeft: xCoord = currentTilePos.X * 16f; break; } float yCoord = 0; switch (genDir) { case GeneralDirection.UpRight: case GeneralDirection.UpLeft: yCoord = currentTilePos.Y * 16f; break; case GeneralDirection.DownRight: case GeneralDirection.DownLeft: yCoord = currentTilePos.Y * 16f + 16f; break; } //relative slope will represent how the slope of the current direction compares to the slope of a line going through the current position //and the intersection between the next horizontal and vertical lines. // //if relative slope is greater than 0, the vertical line will be hit first. //if relative slope is less than 0, the horizontal line will be hit first. //if relative slope rounded to 3 decimals equals 0, then the current direction will hit the corner formed by the vertical and horizontal lines float relativeSlope = Math.Abs((yCoord - position.Y) / (xCoord - position.X)) - Math.Abs(dir.Y / dir.X); Point checkTilePos; if (Math.Abs(relativeSlope) <= .05) { if (WorldGen.TileEmpty(currentTilePos.X, currentTilePos.Y)) { //WorldGen.PlaceTile(currentTilePos.X, currentTilePos.Y, TileID.Bubble, true, true); } else if (WorldGen.SolidOrSlopedTile(currentTilePos.X, currentTilePos.Y)) { //Main.tile[currentTilePos.X, currentTilePos.Y].type = TileID.AmethystGemspark; } //motion will hit the corner, if it can travel far enough if (Math.Abs(xCoord - position.X) > Math.Abs(nextPos.X - position.X)) { //the corner will not be hit before travelling the max distance per iteration. the projectile will not hit a tile break; } TileDef upLeft; TileDef upRight; TileDef downLeft; TileDef downRight; switch (genDir) { case GeneralDirection.UpLeft: checkTilePos = new Point(currentTilePos.X - 1, currentTilePos.Y - 1); upLeft = new TileDef(checkTilePos); break; case GeneralDirection.UpRight: checkTilePos = new Point(currentTilePos.X + 1, currentTilePos.Y - 1); upLeft = new TileDef(checkTilePos.X - 1, checkTilePos.Y); break; case GeneralDirection.DownLeft: checkTilePos = new Point(currentTilePos.X - 1, currentTilePos.Y + 1); upLeft = new TileDef(checkTilePos.X, checkTilePos.Y - 1); break; case GeneralDirection.DownRight: default: checkTilePos = new Point(currentTilePos.X + 1, currentTilePos.Y + 1); upLeft = new TileDef(checkTilePos.X - 1, checkTilePos.Y - 1); break; } upRight = new TileDef(upLeft.coords.X + 1, upLeft.coords.Y); downLeft = new TileDef(upLeft.coords.X, upLeft.coords.Y + 1); downRight = new TileDef(upLeft.coords.X + 1, upLeft.coords.Y + 1); //take care of corner between 2 similar sloped blocks first if ((genDir != GeneralDirection.DownRight && upRight.slope == 3 && downLeft.slope == 3) || (genDir != GeneralDirection.UpLeft && upRight.slope == 2 && downLeft.slope == 3)) { // tiles look like this // /] // /] // or like this // [/ // [/ // hitTile = true; nextPos = new Vector2(xCoord, yCoord); reflectAgainstYEqualsNegativeX(ref dir); currentTilePos = checkTilePos; break; } if ((genDir != GeneralDirection.DownLeft && upLeft.slope == 4 && downRight.slope == 4) || (genDir != GeneralDirection.UpRight && upLeft.slope == 1 && downRight.slope == 1)) { // tiles look like this // \] // \] // or like this // [\ // [\ // hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Stone; nextPos = new Vector2(xCoord, yCoord); reflectAgainstYEqualsX(ref dir); currentTilePos = checkTilePos; break; } } else { //get the next tile position to check, if it's not out of reach if (relativeSlope > 0) { //vertical line will be hit first, if at all if (Math.Abs(xCoord - position.X) > Math.Abs(nextPos.X - position.X)) { //the line will not be hit before travelling the max distance per iteration. the projectile will not hit a tile break; } if (genDir == GeneralDirection.UpLeft || genDir == GeneralDirection.DownLeft) { checkTilePos = new Point(currentTilePos.X - 1, currentTilePos.Y); } else { checkTilePos = new Point(currentTilePos.X + 1, currentTilePos.Y); } } else { //horizontal line will be hit first, if at all if (Math.Abs(yCoord - position.Y) > Math.Abs(nextPos.Y - position.Y)) { //the line will not be hit before travelling the max distance per iteration. the projectile will not hit a tile break; } if (genDir == GeneralDirection.UpLeft || genDir == GeneralDirection.UpRight) { checkTilePos = new Point(currentTilePos.X, currentTilePos.Y - 1); } else { checkTilePos = new Point(currentTilePos.X, currentTilePos.Y + 1); } } Tile checkTile = Main.tile[checkTilePos.X, checkTilePos.Y]; TileDef tileDef = new TileDef(checkTilePos); TileRect tileRect = new TileRect(checkTilePos); if (tileDef.slope != -1) { //check tile is an active, solid/sloped block if (relativeSlope > 0) { //vertical line hit first if ( //check right edge of tile ((genDir == GeneralDirection.UpLeft || genDir == GeneralDirection.DownLeft) && (new int[] { 0, 2, 4 }).Contains(tileDef.slope)) || //check left edge of tile ((genDir == GeneralDirection.UpRight || genDir == GeneralDirection.DownRight) && (new int[] { 0, 1, 3 }).Contains(tileDef.slope))) { //tile has a side along the vertical line hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Copper; reflectAgainstY(ref dir); List <Vector2> interceptList = (new LineEquation(xCoord)).getIntercepts(motion.equation); if (interceptList.Count > 0) { nextPos = interceptList[0]; currentTilePos = checkTilePos; } break; } LineSegment extraSide; switch (tileDef.slope) { case 1: // [\ case 4: // \] extraSide = new LineSegment(tileRect.topLeft, tileRect.bottomRight); break; case 2: // /] case 3: // [/ extraSide = new LineSegment(tileRect.topRight, tileRect.bottomLeft); break; default: //half block if (genDir == GeneralDirection.UpLeft || genDir == GeneralDirection.DownLeft) { //right side extraSide = new LineSegment(tileRect.middleRight, tileRect.bottomRight); } else { //left side extraSide = new LineSegment(tileRect.middleLeft, tileRect.bottomLeft); } break; } List <Vector2> intercepts = extraSide.getIntercepts(motion); if (intercepts.Count > 0) { nextPos = intercepts[0]; hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Lead; switch (tileDef.slope) { case 1: // [\ case 4: // \] reflectAgainstYEqualsX(ref dir); break; case 2: // /] case 3: // [/ reflectAgainstYEqualsNegativeX(ref dir); break; default: //half block reflectAgainstY(ref dir); break; } currentTilePos = checkTilePos; break; } } else { //horizontal line hit first if (genDir == GeneralDirection.UpRight || genDir == GeneralDirection.UpLeft) { //check bottom edge of tile if ((new int[] { 0, 1, 2, 5 }).Contains(tileDef.slope)) { hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.RedBrick; reflectAgainstX(ref dir); nextPos = (new LineEquation(0, yCoord)).getIntercepts(motion.equation)[0]; currentTilePos = checkTilePos; break; } LineSegment slopedSide; if (tileDef.slope == 3) // [/ { slopedSide = new LineSegment(tileRect.topRight, tileRect.bottomLeft); } else // \] { slopedSide = new LineSegment(tileRect.topLeft, tileRect.bottomRight); //slopedSide = new LineSegment(tileRect.topLeft, tileRect.bottomRight); } List <Vector2> intercepts = slopedSide.getIntercepts(motion); if (intercepts.Count > 0) { nextPos = intercepts[0]; hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Cloud; if (tileDef.slope == 3) // [/ { reflectAgainstYEqualsNegativeX(ref dir); } else // \] { reflectAgainstYEqualsX(ref dir); } currentTilePos = checkTilePos; break; } } else { if ((new int[] { 0, 3, 4 }).Contains(tileDef.slope)) { hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Asphalt; reflectAgainstX(ref dir); nextPos = (new LineEquation(0, yCoord)).getIntercepts(motion.equation)[0]; currentTilePos = checkTilePos; break; } LineSegment extraSide; if (tileDef.slope == 1) // [\ { extraSide = new LineSegment(tileRect.topLeft, tileRect.bottomRight); } else if (tileDef.slope == 2) // /] { extraSide = new LineSegment(tileRect.topRight, tileRect.bottomLeft); } else // half block { extraSide = new LineSegment(tileRect.middleLeft, tileRect.middleRight); } List <Vector2> intercepts = extraSide.getIntercepts(motion); if (intercepts.Count > 0) { nextPos = intercepts[0]; hitTile = true; //Main.tile[checkTilePos.X, checkTilePos.Y].type = TileID.Glass; if (tileDef.slope == 1) { reflectAgainstYEqualsX(ref dir); } else if (tileDef.slope == 2) { reflectAgainstYEqualsNegativeX(ref dir); } else { reflectAgainstX(ref dir); } currentTilePos = checkTilePos; } break; } } } //else the check tile is either actuated or a background object. stay in loop and get the next check tile } //if the loop has not been escaped then a tile has not been hit and not all tiles along the projectile's motion have been checked currentTilePos = checkTilePos; //currentTilePos = new Point((int) Math.Floor(nextPos.X / 16f),(int) Math.Floor(nextPos.Y / 16f)); } Vector2 previousPoint = endPoints[endPoints.Count - 1]; endPoints.Add(nextPos); currentDistance += (float)Math.Sqrt(Math.Pow(nextPos.X - previousPoint.X, 2) + Math.Pow(nextPos.Y - previousPoint.Y, 2)); if (i == maxIterations) { i = maxIterations; } position = nextPos; } for (int p = 0; p < endPoints.Count - 1; p++) { Vector2 currentPos = endPoints[p]; Vector2 nextPos = endPoints[p + 1]; Vector2 disp = nextPos - currentPos; float totalDistance = (float)Math.Sqrt(Math.Pow(disp.X, 2) + Math.Pow(disp.Y, 2)); int totalSpawns = (int)Math.Ceiling(totalDistance / maxDistanceBetweenSpawns); Vector2 spawnOffset = disp / totalSpawns; for (int i = 1; i <= totalSpawns; i++) { Vector2 previousPos = currentPos + spawnOffset * (i - 1); int projId = Projectile.NewProjectile(currentPos + spawnOffset * i, new Vector2(0, 0), ModContent.ProjectileType <Projectiles.PaintLaser>(), damage, 0f, player.whoAmI, previousPos.X, previousPos.Y); } } return(false); } /*