Ejemplo n.º 1
0
 public LineIntercept(LineSegment segment, Vector2 point)
 {
     this.segment = segment;
     this.point   = point;
 }
Ejemplo n.º 2
0
        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);
        }        /*