Beispiel #1
0
        public override void RunTick()
        {
            if (this.behavior is Behavior)
            {
                this.behavior.RunTick();
            }

            // Standard Physics
            this.physics.RunPhysicsTick();

            // Animations, if applicable.
            if (this.animate is Animate)
            {
                this.animate.RunAnimationTick(Systems.timer);
            }

            // Check if the enemy is about to run off of a cliff:
            if (Systems.timer.IsTickFrame && this.physics.touch.toFloor)
            {
                if (this.FaceRight)
                {
                    if (!CollideTile.IsBlockingCoord(this.room.tilemap, this.posX + this.bounds.Right + 8, this.posY + this.bounds.Bottom + 10, DirCardinal.Down))
                    {
                        this.SetDirection(false);
                    }
                }
                else
                {
                    if (!CollideTile.IsBlockingCoord(this.room.tilemap, this.posX + this.bounds.Left - 8, this.posY + this.bounds.Bottom + 10, DirCardinal.Down))
                    {
                        this.SetDirection(true);
                    }
                }
            }
        }
Beispiel #2
0
        private void DetermineSlamDistance()
        {
            TilemapLevel tilemap = this.actor.room.tilemap;

            // We know the slammer's starting position.
            short gridX = this.actor.GridX;
            short gridY = this.actor.GridY;

            this.viewY      = this.actor.posY + ((byte)TilemapEnum.TileHeight * 2);
            this.viewHeight = 0;

            // Scan for solid tiles beneath the slammer, up to 17 below (for a full screen)
            for (short testY = (short)(gridY + 2); testY < gridY + 19; testY++)
            {
                if (testY > tilemap.YCount + (byte)TilemapEnum.GapUp)
                {
                    return;
                }

                // If there is a blocking tile at this height below the slammer, we can determine it's final Y-position after a slam:
                if (CollideTile.IsBlockingSquare(tilemap, gridX, testY, DirCardinal.Up) || CollideTile.IsBlockingSquare(tilemap, (short)(gridX + 1), testY, DirCardinal.Up))
                {
                    this.endY       = testY * (byte)TilemapEnum.TileHeight;
                    this.viewHeight = (short)(this.endY - this.viewY - 10);
                    break;
                }
            }
        }
Beispiel #3
0
        public void DropItem()
        {
            if (this.objHeld == null)
            {
                return;
            }

            Item item = this.objHeld;

            item.intangible = Systems.timer.Frame + 7;

            // Check what Main Layer has present at the throw-release tile:
            TilemapLevel tilemap = this.character.room.tilemap;

            bool isBlocked = false;
            bool faceRight = this.character.FaceRight;

            isBlocked = CollideTile.IsBlockingSquare(tilemap, faceRight ? item.GridX2 : item.GridX, item.GridY, DirCardinal.Up);

            // If the drop tiles are blocked, see if we can drop it in the tile below.
            if (isBlocked)
            {
                int limitY = item.GridY * (byte)TilemapEnum.TileHeight + (byte)TilemapEnum.TileHeight;
                int dist   = limitY - (item.posY + item.bounds.Top);

                // If we only have to drop it 24 pixels (or less), we can just lower the item slightly.
                if (dist < 24)
                {
                    item.physics.MoveToPosY(limitY - item.bounds.Top);
                    isBlocked = CollideTile.IsBlockingSquare(tilemap, faceRight ? item.GridX2 : item.GridX, item.GridY, DirCardinal.Up);
                }
            }

            // If the tile is still blocked, then a Y-reposition didn't work. We'll have to move it to character's tile.
            if (isBlocked)
            {
                int limitX;

                // NOTE: MUST have it like this. I don't understand the nuanced difference here, but it works.
                if (faceRight)
                {
                    limitX = item.GridX2 * (byte)TilemapEnum.TileWidth;
                }
                else
                {
                    limitX = item.GridX * (byte)TilemapEnum.TileWidth + (byte)TilemapEnum.TileWidth;
                }

                item.physics.MoveToPosX(limitX - (faceRight ? item.bounds.Right : item.bounds.Left));
            }

            // Assign Minimal Drop Physics (to smooth natural look)
            item.physics.velocity.X = FInt.Create(this.character.physics.velocity.X.RoundInt / 3);
            item.physics.velocity.Y = FInt.Create(-1.5);

            // Play Drop Sound
            this.character.room.PlaySound(Systems.sounds.wooshSubtle, 0.5f, this.character.posX + 16, this.character.posY + 16);

            this.ResetHeldItem();
        }
Beispiel #4
0
        private void DoTeleport()
        {
            CharacterStatus status = this.character.status;

            // End the Teleport Action (to prevent re-teleportation)
            this.character.status.action.EndAction(this.character);

            // Get X, Y Coordinates from Distance and Radian
            float trueRotation = Radians.Normalize(status.actionFloat1);
            int   xCoord       = (int)Radians.GetXFromRotation(trueRotation, status.actionNum1) + character.posX + character.bounds.MidX;
            int   yCoord       = (int)Radians.GetYFromRotation(trueRotation, status.actionNum1) + character.posY + character.bounds.MidY;

            // Make sure teleportation is within world bounds.
            if (yCoord < (byte)TilemapEnum.GapUpPixel || yCoord > this.character.room.Height + (byte)TilemapEnum.GapUpPixel || xCoord < (byte)TilemapEnum.GapLeftPixel || xCoord > this.character.room.Width + (byte)TilemapEnum.GapRightPixel)
            {
                this.character.room.PlaySound(Systems.sounds.disableCollectable, 0.5f, this.character.posX + 16, this.character.posY + 16);
                return;
            }

            TilemapLevel tilemap = character.room.tilemap;

            // Make sure teleportation is to a valid open area. Blocking tiles will prevent teleportation.
            int xMid = xCoord - this.character.bounds.MidX;
            int yMid = yCoord - this.character.bounds.MidY;

            bool upLeft    = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Left, yMid + character.bounds.Top - 1, DirCardinal.None);
            bool upRight   = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Right, yMid + character.bounds.Bottom - 1, DirCardinal.None);
            bool downLeft  = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Left, yMid + character.bounds.Top - 1, DirCardinal.None);
            bool downRight = CollideTile.IsBlockingCoord(tilemap, xMid + character.bounds.Right, yMid + character.bounds.Bottom - 1, DirCardinal.None);

            // If all positions are blocked, prevent teleport.
            if (upLeft && upRight && downLeft && downRight)
            {
                this.character.room.PlaySound(Systems.sounds.disableCollectable, 0.5f, this.character.posX + 16, this.character.posY + 16);
                return;
            }

            // If some positions are blocked, adjust position:
            if (upLeft && downLeft)
            {
                xMid += 12;
            }
            if (upRight && downRight)
            {
                xMid -= 12;
            }
            if (upLeft && upRight)
            {
                yMid += 12;
            }
            if (downLeft && downRight)
            {
                yMid -= 12;
            }

            this.character.room.PlaySound(Systems.sounds.pop, 1f, this.character.posX + 16, this.character.posY + 16);

            // Teleport Character
            this.character.physics.MoveToPos(xMid, yMid);
        }
Beispiel #5
0
        public override bool RunImpact(RoomScene room, GameObject actor, short gridX, short gridY, DirCardinal dir)
        {
            // Characters interact with Chest:
            if (actor is Character)
            {
                byte subType = room.tilemap.GetMainSubType(gridX, gridY);

                // If the chest is open, no interactions are allowed:
                if (subType == (byte)ChestSubType.Open)
                {
                    return(false);
                }

                Character character = (Character)actor;

                // Make sure the character is fully within the chest tile.
                if (!CollideTile.IsWithinTile(character, gridX, gridY))
                {
                    return(false);
                }

                // The Character must be pressing the interaction key to open the chest.
                if (!character.input.isPressed(IKey.YButton))
                {
                    return(false);
                }

                // If the chest is locked, must have a key:
                if (subType == (byte)ChestSubType.Locked)
                {
                    // Remove the Key, Unlock the Chest.
                    if (!character.trailKeys.RemoveKey())
                    {
                        room.PlaySound(Systems.sounds.click3, 1f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight);
                        return(false);
                    }

                    room.PlaySound(Systems.sounds.unlock, 1f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight);
                }
                else
                {
                    room.PlaySound(Systems.sounds.click2, 0.5f, gridX * (byte)TilemapEnum.TileWidth, gridY * (byte)TilemapEnum.TileHeight);
                }

                this.OpenChest(room, gridX, gridY);
            }

            return(false);
        }
Beispiel #6
0
        public override bool Activate()
        {
            // Make sure the power can be activated
            if (!this.CanActivate())
            {
                return(false);
            }

            // References
            Character character = this.character;

            // Determine Starting Position of Projectile relative to Character
            int posX = character.posX + character.bounds.MidX + (character.FaceRight ? 10 : -30);
            int posY = character.posY + character.bounds.Top + 5;

            // Play Sound
            character.room.PlaySound(this.sound, 1f, posX, posY);

            // Check if the tile placement is blocked:
            TilemapLevel tilemap = this.character.room.tilemap;

            bool isBlocked = CollideTile.IsBlockingCoord(tilemap, posX + 10 + (character.FaceRight ? 6 : -6), posY + 10, character.FaceRight ? DirCardinal.Right : DirCardinal.Left);

            // Prevent Throw
            if (isBlocked)
            {
                return(false);
            }

            // Prepare Velocity
            FInt velX = character.FaceRight ? this.xVel : this.xVel.Inverse;
            FInt velY = this.yVel;

            // Affect the Y-Velocity of the projectile if holding UP or DOWN
            this.AffectByInput(ref velX, ref velY);

            // Apply Character's Momentum (if applicable)
            if (this.multMomentum > 0)
            {
                velX += character.physics.velocity.X * this.multMomentum;
                velY += character.physics.velocity.Y * this.multMomentum * FInt.Create(0.5);
            }

            // Launch Projectile
            this.Launch(posX, posY, velX, velY);

            return(true);
        }
Beispiel #7
0
        // Returns TRUE if the character can phase to the horizontal location.
        public bool TestPhasingHorizontal(Character character, TilemapLevel tilemap, short toX, DirCardinal dir)
        {
            bool blocking = CollideTile.IsBlockingSquare(tilemap, toX, character.GridY, dir);

            if (blocking)
            {
                return(false);
            }

            if (character.GridY != character.GridY2)
            {
                blocking = CollideTile.IsBlockingSquare(tilemap, toX, character.GridY2, dir);
            }

            return(!blocking);
        }
Beispiel #8
0
        // Returns TRUE if the character can phase to the vertical location.
        public bool TestPhasingVertical(Character character, TilemapLevel tilemap, short toY, DirCardinal dir)
        {
            bool blocking = CollideTile.IsBlockingSquare(tilemap, character.GridX, toY, dir);

            if (blocking)
            {
                return(false);
            }

            if (character.GridX != character.GridX2)
            {
                blocking = CollideTile.IsBlockingSquare(tilemap, character.GridX2, toY, dir);
            }

            return(!blocking);
        }
Beispiel #9
0
        public void SolidTileCollision()
        {
            Character ch   = this.character;
            Physics   phys = ch.physics;

            // Create Tiles in diamond pattern.
            this.tilemap.SetMainTile(10, 8, (byte)TileEnum.Brick, 0);              // Position at 480, 384
            this.tilemap.SetMainTile(9, 9, (byte)TileEnum.Brick, 0);               // Position at 432, 432
            this.tilemap.SetMainTile(10, 10, (byte)TileEnum.Brick, 0);             // Position at 480, 480
            this.tilemap.SetMainTile(11, 9, (byte)TileEnum.Brick, 0);              // Position at 528, 432

            // --- Simultaneous Up AND Right Tile Collisions; not corner --- //
            phys.SetGravity(FInt.Create(0));             // End Gravity
            phys.MoveToPos(480 - ch.bounds.Right - 3, 480);
            phys.velocity = FVector.Create(6, -4);       // Character moving up-right.

            this.VerifyGridPos(ch, 9, 10, 9, 10);

            phys.RunPhysicsTick();
            ch.RunTick();

            CollideTile.RunTileCollision(ch);

            Debug.Assert(ch.posX + ch.bounds.Right == 480, "Character posX should be 480.");
            Debug.Assert(ch.posY + ch.bounds.Top == 480, "Character posY should be 480.");

            // --- Simultaneous Down AND Left Tile Collisions; not corner --- //
            phys.MoveToPos(528 - ch.bounds.Left + 2, 432 - ch.bounds.Bottom - 2);
            phys.velocity = FVector.Create(-5, 7);                                      // Character moving down-left.

            this.VerifyGridPos(ch, 11, 8, 11, 8);

            phys.RunPhysicsTick();
            ch.RunTick();

            CollideTile.RunTileCollision(ch);

            Debug.Assert(ch.posX + ch.bounds.Left == 528, "Character posX should be 528.");
            Debug.Assert(ch.posY + ch.bounds.Bottom == 432, "Character posY should be 432.");

            // Delete Tiles
            this.tilemap.ClearMainLayer(10, 8);
            this.tilemap.ClearMainLayer(9, 9);
            this.tilemap.ClearMainLayer(10, 10);
            this.tilemap.ClearMainLayer(11, 9);
        }
Beispiel #10
0
        public override bool Activate()
        {
            // Make sure the power can be activated
            if (!this.CanActivate())
            {
                return(false);
            }

            // References
            Character character = this.character;

            // Determine Starting Position of Projectile relative to Character
            int posX = character.posX + character.bounds.MidX + (character.FaceRight ? 6 : -30);
            int posY = character.posY + character.bounds.Top + 5;

            // Play Sound
            character.room.PlaySound(this.sound, 1f, posX, posY);

            // Check if the tile placement is blocked (only applies to bolts that collide with tiles).
            if (this is BoltBlue)
            {
                TilemapLevel tilemap = this.character.room.tilemap;

                bool isBlocked = CollideTile.IsBlockingCoord(tilemap, posX + (character.FaceRight ? 10 : 4), posY, character.FaceRight ? DirCardinal.Right : DirCardinal.Left);

                // Prevent Throw
                if (isBlocked)
                {
                    return(false);
                }
            }

            // Prepare Velocity
            FInt velX = character.FaceRight ? FInt.Create(this.xVel) : FInt.Create(-this.xVel);
            FInt velY = FInt.Create(this.yVel);

            // Affect the Y-Velocity of the projectile if holding UP or DOWN
            this.AffectByInput(ref velX, ref velY);

            // Launch Projectile
            this.Launch(character, posX, posY, velX, velY);

            return(true);
        }
Beispiel #11
0
        public void ThrowItem(bool useXMomentum = false)
        {
            if (this.objHeld == null)
            {
                return;
            }
            Item item = this.objHeld;

            // Item will release in the direction the character does.
            item.SetDirection(this.character.FaceRight);

            // Check what Main Layer has present at the throw-release tile:
            TilemapLevel tilemap = this.character.room.tilemap;

            bool isBlocked = CollideTile.IsBlockingSquare(tilemap, item.GridX, item.GridY, DirCardinal.Up);

            if (!isBlocked && item.GridX != item.GridX2)
            {
                isBlocked = CollideTile.IsBlockingSquare(tilemap, item.GridX2, item.GridY, DirCardinal.Up);
            }

            // Prevent Throw
            if (isBlocked)
            {
                this.DropItem();
                return;
            }

            // Assign Item Physics + Thrown Properties
            item.intangible         = Systems.timer.Frame + 5;
            item.releasedMomentum   = useXMomentum ? (sbyte)Math.Round(this.character.physics.velocity.X.RoundInt / 2.5) : (sbyte)0;
            item.physics.velocity.X = FInt.Create(item.releasedMomentum);
            item.physics.velocity.Y = FInt.Create(-item.ThrowStrength);

            // Play Throw Sound
            this.character.room.PlaySound(Systems.sounds.wooshSubtle, 1f, this.character.posX + 16, this.character.posY + 16);

            // No longer holding object:
            this.ResetHeldItem();
        }
Beispiel #12
0
        private void PlaceDetectorsAbove(RoomScene room, short gridX, short gridY)
        {
            TilemapLevel tilemap = room.tilemap;

            // Scan for solid tiles above the flag, up to 18 above (for a full screen)
            for (short testY = (short)(gridY - 1); testY > gridY - 18; testY--)
            {
                if (testY < (byte)TilemapEnum.GapUp)
                {
                    return;
                }

                // If there is a blocking tile at this grid sqare, stop placements.
                if (CollideTile.IsBlockingSquare(tilemap, gridX, testY, DirCardinal.Down))
                {
                    return;
                }

                // Otherwise, add a Detector.
                room.tilemap.SetMainTile(gridX, testY, (byte)TileEnum.DetectCheckpointPass, 0);
            }
        }