Beispiel #1
0
        public DialogBox(string[] text, string font, float sizePx, Game1 game, Level parent, Vector2 position = default(Vector2)) : base("", font, sizePx, game, parent, "WalkieTalkie", position, Chunk.Down)
        {
            LeftPadding   = 65;
            RightPadding  = 5;
            TopPadding    = 5;
            BottomPadding = 5;

            AvatarTexture = game.TextureCache["walkie_talkie"];

            Avatar = new AnimatedSprite(AvatarTexture, game, new Vector2(AvatarTexture.Bounds.Width, AvatarTexture.Bounds.Height));
            Avatar.Add("idle", 0, 1, 100);
            Avatar.Play("idle");

            TextArray = text;

            MaxLines = (Background.Height - TopPadding - BottomPadding) / sizePx;

            SetText(TextArray[0]);
            CurLetters = 1;
            //CurMaxLetters = Text.Length;
            CurLines    = Text.Split('\n', StringSplitOptions.RemoveEmptyEntries);
            CurNumLines = CurLines.Length;

            CurMaxLetters = 0;
            for (int i = 0; i < Math.Min(Math.Floor(MaxLines), CurNumLines); ++i)
            {
                CurMaxLetters++;
                CurMaxLetters += CurLines[i].Length;
            }
            CurMaxLetters--;
        }
Beispiel #2
0
 private void Close(Chunk chunk)
 {
     Sprite.Play("closed");
     State = EState.Closed;
     doorCollision.Open = false;
     chunk.SolidTiles[chunk.GetTileLocation(Position - Vector2.UnitY * Chunk.TileSize / 2)] = (uint)Chunk.Colors.AerialDroneWall;
     chunk.SolidTiles[chunk.GetTileLocation(Position + Vector2.UnitY * Chunk.TileSize / 2)] = (uint)Chunk.Colors.AerialDroneWall;
 }
Beispiel #3
0
        public TextBox(string text, string font, float sizePx, Game1 game, Level parent,
                       string type     = "Debug", Vector2 position = new Vector2(), int anchor = 0,
                       int leftPadding = 0, int rightPadding       = 0, int topPadding         = 0, int bottomPadding = 0) : base(game, parent)
        {
            Background = game.TextureCache[Backgrounds[type]];
            Text       = text;
            Font       = font;
            SizePx     = sizePx;

            TopPadding = topPadding;

            BackgroundSprite = new AnimatedSprite(Background, game, new Vector2(Background.Bounds.Width, Background.Bounds.Height));
            BackgroundSprite.Add("idle", 0, 1, 100);
            BackgroundSprite.Play("idle");

            Position = position;
            Anchor   = anchor;
        }
Beispiel #4
0
        public void HearSound(Vector2 position, float volume, Chunk chunk)
        {
            if (PositionKnown > 0)
            {
                return;
            }

            float sqrDist = (Position - position).LengthSquared();

            if (sqrDist > SoundEngine.AudibleDistance * SoundEngine.AudibleDistance)
            {
                return;
            }

            float dist = (float)Math.Sqrt(sqrDist);

            if (chunk.IntersectLine(position, Position - position, 1, out float temp, false))
            {
                volume /= 2;
            }

            float sensitivity = (chunk.ChunkAlarmState ? AlertSensitivity : ClearSensitivity);

            volume -= dist / sensitivity;

            if (volume > 0)
            {
                float precision = Math.Min(1, volume / BaseVolume);

                float angle = (float)Game.RNG.NextDouble() * 2 * (float)Math.PI;

                float distOffset = (1 - precision) * HearingPrecision;

                Vector2 dir = new Vector2((float)Math.Sin(angle), (float)Math.Cos(angle));

                var point1 = new Vector2(dir.Y, -dir.X);
                point1.Normalize();
                point1 *= Size.X;
                var point2 = -point1;

                if (chunk.IntersectLine(position + point1, dir, distOffset, out float distToIntersect1, false, true))
                {
                    distOffset = distToIntersect1;
                }

                if (chunk.IntersectLine(position + point2, dir, distOffset, out float distToIntersect2, false, true))
                {
                    distOffset = distToIntersect2;
                }

                if (State == AIState.Searching)
                {
                    if (Target(position + dir * distOffset, chunk, AIState.Targeting))
                    {
                        FinishPath = () => AlertSignal.Play("alert");
                    }
                }
                else if (State != AIState.Targeting && State != AIState.Investigating)
                {
                    if (Target(position + dir * distOffset, chunk, AIState.Investigating))
                    {
                        FinishPath = () =>
                        {
                            AlertSignal.Play("noise");
                            Game.SoundEngine.Play("Enemy_Alarmed", Position, 1);
                            ViewCone.SetColor(ConeEntity.InspectColor);
                        }
                    }
                    ;
                }
            }
        }
Beispiel #5
0
        public override void Update(Chunk chunk)
        {
            if (FlyingSound == null)
            {
                FlyingSound = Game.SoundEngine.Play("Enemy_DroneFly", Position, 1, true);
            }

            if (PositionKnown > 0)
            {
                --PositionKnown;
            }

            float dt = Game1.DeltaT;

            Velocity = new Vector2();

            switch (State)
            {
            case AIState.Patrolling:
                if (MoveTo(WanderLocation, PatrolSpeed))
                {
                    Wait();
                }
                break;

            case AIState.Searching:
                if (MoveTo(WanderLocation, SearchSpeed))
                {
                    Velocity = new Vector2(0);
                    bool foundSearch = false;
                    for (int i = 0; i < WanderSearchAttempts; ++i)
                    {
                        if (FindWander(TargetLocation, PatrolRange, chunk))
                        {
                            foundSearch = true;
                            break;
                        }
                    }
                    if (!foundSearch)
                    {
                        if (Target(TargetLocation, chunk, AIState.Targeting))
                        {
                            FinishPath = () => { };
                        }
                    }
                }
                break;

            case AIState.CursorySearching:
                if (MoveTo(WanderLocation, PatrolSpeed))
                {
                    Velocity = new Vector2(0);
                    bool foundSearch = false;
                    for (int i = 0; i < WanderSearchAttempts; ++i)
                    {
                        if (FindWander(TargetLocation, PatrolRange, chunk))
                        {
                            foundSearch = true;
                            break;
                        }
                    }
                    if (!foundSearch)
                    {
                        if (Target(TargetLocation, chunk, AIState.Investigating))
                        {
                            FinishPath = () => { };
                        }
                    }
                }

                StateTimer -= dt;
                if (StateTimer <= 0)
                {
                    Return(chunk);
                }
                break;

            case AIState.Waiting:
                StateTimer += dt;
                if (StateTimer <= 0.05F * WaitTime)
                {
                }
                if (StateTimer <= 0.25F * WaitTime)
                {
                    Direction += dt * WaitAngularVelocity;
                }
                else if (StateTimer <= 0.3F * WaitTime)
                {
                }
                else if (StateTimer <= 0.7F * WaitTime)
                {
                    Direction -= dt * WaitAngularVelocity;
                }
                else if (StateTimer <= 0.75F * WaitTime)
                {
                }
                else if (StateTimer <= 0.95F * WaitTime)
                {
                    Direction += dt * WaitAngularVelocity;
                }
                else if (StateTimer <= WaitTime)
                {
                }
                else
                {
                    bool found = false;
                    for (int i = 0; i < WanderSearchAttempts; ++i)
                    {
                        if (FindWander(Spawn, PatrolRange, chunk))
                        {
                            found = true;
                            break;
                        }
                    }

                    if (!found)
                    {
                        Return(chunk);
                    }
                    else
                    {
                        State = AIState.Patrolling;
                    }
                }
                break;

            case AIState.Targeting:
                Vector2 nextPos = NextNode < Path.Count - 1 ? Path[NextNode] : TargetLocation;
                if (MoveTo(nextPos, TargetSpeed))
                {
                    Velocity = new Vector2();
                    ++NextNode;

                    nextPos = NextNode < Path.Count - 1 ? Path[NextNode] : TargetLocation;

                    if (NextNode >= Path.Count)
                    {
                        Search(nextPos, chunk, float.PositiveInfinity);
                    }
                    else
                    {
                        MoveTo(nextPos, TargetSpeed);
                    }
                }
                break;

            case AIState.Investigating:
                if (MoveTo(Path[NextNode], SearchSpeed))
                {
                    Velocity = new Vector2();
                    ++NextNode;
                    if (NextNode >= Path.Count)
                    {
                        Search(Path[NextNode - 1], chunk, SearchTime, true);
                    }
                    else
                    {
                        MoveTo(Path[NextNode], SearchSpeed);
                    }
                }
                break;

            case AIState.Returning:
                if (MoveTo(Path[NextNode], PatrolSpeed))
                {
                    ++NextNode;
                    if (NextNode >= Path.Count)
                    {
                        Wait();
                    }
                }
                break;
            }

            if (Pathfinding != null)
            {
                if (Pathfinding.IsCompleted)
                {
                    var newPath = Pathfinding.Result;

                    Pathfinding.Dispose();
                    Pathfinding = null;

                    if (newPath.Count > 1)
                    {
                        Path = newPath;

                        TargetLocation = Path.Last();

                        NextNode = 1;
                    }

                    State = NextState;

                    FinishPath.Invoke();
                }
            }

            { // Kill if touched.
                if (!chunk.Level.Player.IsHiding &&
                    chunk.Level.Player.DeathTimer <= 0 &&
                    GetBoundingBox().Intersects(chunk.Level.Player.GetBoundingBox()))
                {
                    chunk.Level.Player.Kill();
                }
            }

            if (State == AIState.Targeting || State == AIState.Searching)
            {
                Sprite.Play("chase");
            }
            else
            {
                Sprite.Play("idle");
            }

            Position += dt * Velocity;
            ViewCone.UpdatePosition(Position);
            ViewCone.Middle = Direction;
            ViewCone.Update(chunk);

            AlertSignal.Update(dt);
            Sprite.Update(dt);

            FlyingSound.Position = Position;

            base.Update(chunk);
        }
Beispiel #6
0
        public override void Update(Chunk chunk)
        {
            float dt = Game1.DeltaT;

            Controller.Update();
            Sprite.Update(dt);

            if (Controller.Pause)
            {
                Game.Paused = true;
            }

            if (0 < DeathTimer)
            {
                DeathTimer -= dt;
                if (DeathTimer <= 0)
                {
                    chunk.Die(this);
                }
                if (Grounded)
                {
                    Velocity.X = 0;
                }
            }

            if (Controller.Crouch && !Controller.Was.Crouch)
            {
                IsCrouched = !IsCrouched;
            }

            bool hide = Controller.Hide && !Controller.Was.Hide;
            bool jump = Controller.Jump && !Controller.Was.Jump;

            //// Perform movement stepping.
            //// !! This code should never change Position !!
            // Check for neighbors
            Object down = chunk.CollidePoint(new Vector2(Position.X,
                                                         Position.Y - Size.Y - 1));
            Object left = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1,
                                                         Position.Y));
            Object right = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1,
                                                          Position.Y));
            Object leftCorner = chunk.CollidePoint(new Vector2(Position.X - Size.X - 1,
                                                               Position.Y - Size.Y - 1));
            Object rightCorner = chunk.CollidePoint(new Vector2(Position.X + Size.X + 1,
                                                                Position.Y - Size.Y - 1));

            // Apply gravity
            Velocity.Y -= dt * Gravity;

            chunk.ForEachCollidingTile(this, (tile, pos) => {
                if (tile is TileSpike && State != PlayerState.Dying)
                {
                    Kill();
                }
                else if (tile is TileGoal)
                {
                    Game.SoundEngine.Play("win");
                    Game.ShowScore();
                }
            });

            switch (State)
            {
            case PlayerState.Climbing:
            case PlayerState.Normal:
                chunk.ForEachCollidingEntity(this, (entity) => {
                    if (entity is Pickup && !chunk.Level.Alarm.IsRaised)
                    {
                        Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36));
                        Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos);
                        if (Controller.Interact)
                        {
                            if (chunk.NextItem < chunk.StoryItems.Length)
                            {
                                State      = PlayerState.QueueInCall;
                                ItemDialog = true;
                            }
                            chunk.Die(entity);
                        }
                    }
                    else if (entity is HidingSpot)
                    {
                        Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36));
                        Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos);
                        if (hide)
                        {
                            TargetSpot = entity.Position;
                            hide       = false;
                            State      = PlayerState.QueueHide;
                        }
                    }
                    else if (entity is Door && ((Door)entity).State == Door.EState.Closed)
                    {
                        if (entity.GetBoundingBox().Bottom <= GetBoundingBox().Bottom)
                        {
                            float dir = Math.Sign(Position.X - entity.Position.X);
                            if (-Sprite.Direction == dir)
                            {
                                Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(dir * 1.1F * Chunk.TileSize, 32));
                                Game.TextEngine.QueueButton(TextEngine.Button.Y, buttonPos);
                                if (entity == TargetEntity)
                                {
                                    if (Controller.Interact && !IsCrouched)
                                    {
                                        InteractTimer -= Game1.DeltaT;
                                        if (InteractTimer <= 0)
                                        {
                                            State      = PlayerState.QueueCrash;
                                            TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0);
                                        }
                                    }
                                    else
                                    {
                                        State      = PlayerState.QueueDoor;
                                        TargetSpot = entity.Position + new Vector2(dir * (0.5F * Chunk.TileSize + 1), 0);
                                    }
                                }
                                else
                                {
                                    if (Controller.Interact)
                                    {
                                        TargetEntity  = entity;
                                        InteractTimer = InteractHold;
                                    }
                                }
                            }
                        }
                    }
                    else if (entity is ButtonPrompt)
                    {
                        Vector2 buttonPos = Game.TextEngine.TranslateToWindow(entity.Position + new Vector2(0, 36));
                        ((ButtonPrompt)entity).DrawPrompt();
                    }
                    else if (entity is DialogTrigger)
                    {
                        if (chunk.Level.NextTrigger < chunk.Level.TriggeredDialogs.Length)
                        {
                            State      = PlayerState.QueueInCall;
                            ItemDialog = false;
                        }

                        chunk.Die(entity);
                    }
                    else if (entity is AlarmTrigger)
                    {
                        ((AlarmTrigger)entity).Triggered = true;
                        chunk.Level.Alarm.Detected       = true;
                        chunk.Level.Alarm.Alert(Position, chunk);
                    }
                });

                if (State == PlayerState.QueueHide ||
                    State == PlayerState.QueueDoor ||
                    State == PlayerState.QueueCrash ||
                    State == PlayerState.QueueInCall)
                {
                    break;
                }

                if (left != null || right != null || (State == PlayerState.Climbing && (leftCorner != null || rightCorner != null)))
                {
                    HasWallJumped = false;
                    State         = PlayerState.Normal;
                    if (Controller.Climb)
                    {
                        State = PlayerState.Climbing;
                        if (Controller.MoveUp && Velocity.Y < ClimbSpeed)
                        {
                            Velocity.Y = +ClimbSpeed;
                        }
                        else if (Controller.MoveDown)
                        {
                            Velocity.Y = -ClimbSpeed;
                        }
                        else if (Velocity.Y <= ClimbSpeed)
                        {
                            Velocity.Y = 0;
                        }

                        if (Velocity.X != 0)
                        {
                            State = PlayerState.Normal;
                        }

                        // Push over corners
                        if (leftCorner != null && left == null && Sprite.Direction == -1)
                        {
                            Velocity.X = -150;
                            Velocity.Y = ClimbSpeed;
                        }
                        if (rightCorner != null && right == null && Sprite.Direction == +1)
                        {
                            Velocity.X = +150;
                            Velocity.Y = ClimbSpeed;
                        }
                    }
                    else if (Velocity.Y < 0)
                    {
                        Velocity.Y *= WallSlideFriction;
                    }

                    if (jump && (!HasWallJumped || CanRepeatWallJump))
                    {
                        if (right != null && (!Grounded))
                        {
                            MakeSound(chunk, "walljump");
                            Velocity.X    = -WallJumpVelocity.X;
                            Velocity.Y    = WallJumpVelocity.Y;
                            HasWallJumped = true;
                            jump          = false;
                        }
                        else if (left != null && (!Grounded))
                        {
                            MakeSound(chunk, "walljump");
                            Velocity.X    = WallJumpVelocity.X;
                            Velocity.Y    = WallJumpVelocity.Y;
                            HasWallJumped = true;
                            jump          = false;
                        }
                    }
                }
                else
                {
                    State = PlayerState.Normal;
                }

                if (Grounded)
                {
                    SoundFrame    = -1;
                    HasWallJumped = false;
                    if (jump)
                    {
                        IsCrouched = false;
                        MakeSound(chunk, "jump");
                        jump       = false;
                        Velocity.Y = JumpSpeed;
                        LongJump   = LongJumpTime * dt;
                    }
                    else if (!chunk.ChunkAlarmState && Controller.Call && !Controller.Was.Call)
                    {
                        State = PlayerState.QueueOutCall;
                    }
                }

                if (State == PlayerState.Normal || Grounded)
                {
                    float max = (IsCrouched) ? CrouchSpeed : MaxVel;
                    if (Controller.MoveRight && Velocity.X < max)
                    {
                        // Allow quick turns on the ground
                        if (Velocity.X < 0 && Grounded)
                        {
                            Velocity.X = 0;
                        }
                        Velocity.X += AccelRate * dt;
                    }
                    else if (Controller.MoveLeft && -max < Velocity.X)
                    {
                        // Allow quick turns on the ground
                        if (0 < Velocity.X && Grounded)
                        {
                            Velocity.X = 0;
                        }
                        Velocity.X -= AccelRate * dt;
                    }
                    else if (!Controller.MoveLeft && !Controller.MoveRight)
                    {
                        // Deaccelerate in the air to accomodate wall jumps
                        if (Grounded || Math.Abs(Velocity.X) < DeaccelRate * dt)
                        {
                            Velocity.X = 0;
                        }
                        else
                        {
                            Velocity.X -= Math.Sign(Velocity.X) * DeaccelRate * dt;
                        }
                    }
                    else if (IsCrouched && max < Math.Abs(Velocity.X))
                    {
                        Velocity.X = Math.Sign(Velocity.X) * max;
                    }
                }

                if (Controller.Jump && 0 < LongJump)
                {
                    Velocity.Y += AccelRate * dt;
                }
                else
                {
                    LongJump = 0;
                }


                break;

            case PlayerState.QueueHide:
                if (Position.X < TargetSpot.X && Velocity.X < MaxVel)
                {
                    // Allow quick turns on the ground
                    if (Velocity.X < 0 && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X += AccelRate * dt;
                }
                else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X)
                {
                    // Allow quick turns on the ground
                    if (0 < Velocity.X && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X -= AccelRate * dt;
                }

                if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt)
                {
                    HasWallJumped = false;
                    State         = PlayerState.Hiding;

                    Position   = TargetSpot + new Vector2(0, Size.Y - Chunk.TileSize / 2);
                    Velocity.X = 0;
                }

                if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize)
                {
                    State = PlayerState.Normal;
                }
                break;

            case PlayerState.Hiding:
                Velocity.X = 0;
                Velocity.Y = 0;
                if (hide)
                {
                    State = PlayerState.Normal;
                }
                break;

            case PlayerState.QueueDoor:
                if (Position.X < TargetSpot.X && Velocity.X < MaxVel)
                {
                    // Allow quick turns on the ground
                    if (Velocity.X < 0 && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X += AccelRate * dt;
                }
                else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X)
                {
                    // Allow quick turns on the ground
                    if (0 < Velocity.X && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X -= AccelRate * dt;
                }

                if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * dt)
                {
                    HasWallJumped = false;
                    State         = PlayerState.OpeningDoor;

                    Position.X = TargetSpot.X;
                    Velocity.X = 0;
                }

                if (Position.Y - Size.Y < TargetSpot.Y - Chunk.TileSize)
                {
                    State = PlayerState.Normal;
                }
                break;

            case PlayerState.OpeningDoor:
                Velocity.X = 0;
                Velocity.Y = 0;
                if (Sprite.Frame == 78)
                {
                    ((Door)TargetEntity).Interact(chunk, false, TargetEntity.Position.X < Position.X);
                }

                if (Sprite.Frame == 0)
                {
                    State        = PlayerState.Normal;
                    TargetEntity = null;
                }
                break;

            case PlayerState.QueueCrash:
                if (Position.X < TargetSpot.X && Velocity.X < MaxVel)
                {
                    // Allow quick turns on the ground
                    if (Velocity.X < 0 && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X += AccelRate * dt;
                }
                else if (Position.X > TargetSpot.X && -MaxVel < Velocity.X)
                {
                    // Allow quick turns on the ground
                    if (0 < Velocity.X && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    Velocity.X -= AccelRate * dt;
                }

                if (Math.Abs(Position.X - TargetSpot.X) <= MaxVel * (dt + 0.6F / 4))
                {
                    HasWallJumped = false;
                    State         = PlayerState.CrashDoor;
                    TargetSpot    = TargetSpot + 999 * Vector2.UnitX * Math.Sign(TargetEntity.Position.X - Position.X);
                    Velocity.X    = MaxVel * Math.Sign(TargetSpot.X - Position.X);
                }
                break;

            case PlayerState.CrashDoor:

                Velocity.Y = 0;
                if (Sprite.Frame >= 88 && Sprite.Frame <= 91)
                {
                    if (Velocity.X < 0 && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    if (Velocity.X < MaxVel)
                    {
                        Velocity.X += Math.Sign(TargetSpot.X - Position.X) * 0.5F * AccelRate * dt;
                    }
                }
                else
                {
                    if (Velocity.X < 0 && Grounded)
                    {
                        Velocity.X = 0;
                    }
                    if (Velocity.X < MaxVel)
                    {
                        Velocity.X += Math.Sign(TargetSpot.X - Position.X) * AccelRate * dt;
                    }
                }

                if (Sprite.Frame == 88)
                {
                    ((Door)TargetEntity).Interact(chunk, true, TargetEntity.Position.X < Position.X);
                }

                if (Sprite.Frame == 6)
                {
                    State        = PlayerState.Normal;
                    TargetEntity = null;
                }
                break;

            case PlayerState.QueueInCall:
                Velocity.X = 0;
                if (Sprite.Frame == 75)
                {
                    CallTimer -= dt;
                    if (CallTimer == float.PositiveInfinity)
                    {
                        State     = PlayerState.Normal;
                        CallTimer = 0;
                        break;
                    }
                    if (CallTimer < 0)
                    {
                        if (ItemDialog)
                        {
                            chunk.Level.OpenDialogBox(chunk.StoryItems[chunk.NextItem++]);
                        }
                        else
                        {
                            chunk.Level.OpenDialogBox(chunk.Level.TriggeredDialogs[chunk.Level.NextTrigger++]);
                        }

                        CallTimer = float.PositiveInfinity;
                    }
                }
                else
                {
                    CallTimer = CallDuration;
                }
                break;

            case PlayerState.QueueOutCall:
                Velocity.X = 0;
                if (Sprite.Frame == 75)
                {
                    CallTimer -= dt;
                    if (CallTimer == float.PositiveInfinity)
                    {
                        State     = PlayerState.Normal;
                        CallTimer = 0;
                        break;
                    }
                    if (CallTimer < 0)
                    {
                        chunk.Level.OpenDialogBox(Level.RandomDialogs[chunk.Level.NextRandomDialog++]);

                        CallTimer = float.PositiveInfinity;
                    }
                }
                else
                {
                    CallTimer = CallDuration;
                }
                break;

            case PlayerState.Dying:
                break;
            }

            if (0 < LongJump)
            {
                LongJump -= dt;
                if (Velocity.Y < 0)
                {
                    LongJump = 0;
                }
            }

            bool HardFall = (Velocity.Y < HardFallVelocity);

            // Now that all movement has been updated, check for collisions
            HandleCollisions(dt, chunk, true);

            if (Grounded && HardFall)
            {
                MakeSound(chunk, "land", 80);
            }

            // Animations
            StopSoundLoop = true;
            switch (State)
            {
            case PlayerState.QueueInCall:
            case PlayerState.QueueOutCall:
                if (CallTimer == CallDuration)
                {
                    Sprite.Play("call");
                    LoopSound("call");
                }
                break;

            case PlayerState.QueueDoor:
            case PlayerState.QueueHide:
            case PlayerState.Normal:
                if ((Velocity.Y < 0 && (left != null || right != null)))
                {
                    Sprite.Play("slide");
                    LoopSound("slide");
                    // Force direction to face wall
                    if (left != null)
                    {
                        Sprite.Direction = -1;
                    }
                    if (right != null)
                    {
                        Sprite.Direction = +1;
                    }
                }
                else
                {
                    if (0 < Velocity.Y)
                    {
                        Sprite.Play("jump");
                    }
                    else if (Velocity.Y < 0)
                    {
                        Sprite.Play("fall");
                    }
                    else if (Velocity.X != 0)
                    {
                        if (IsCrouched)
                        {
                            Sprite.Play("crouchwalk");
                            if (Sprite.Frame == 58 || Sprite.Frame == 63)
                            {
                                MakeSound(chunk, chunk.IsOutside ? "crouch_outside" : "crouch_inside", 5);
                            }
                        }
                        else
                        {
                            Sprite.Play("run");
                            if (Sprite.Frame == 10 || Sprite.Frame == 18)
                            {
                                MakeSound(chunk, chunk.IsOutside ? "run_outside" : "run_inside", 70);
                            }
                        }
                    }
                    else
                    {
                        SoundFrame = 0;
                        if (IsCrouched)
                        {
                            Sprite.Play("crouch");
                        }
                        else
                        {
                            Sprite.Play("idle");
                        }
                    }
                }
                break;

            case PlayerState.Climbing:
                Sprite.Play("climb");
                if (Sprite.Frame == 26 || Sprite.Frame == 31)
                {
                    MakeSound(chunk, "climb", 20);
                }

                if (Velocity.Y < 0)
                {
                    Sprite.FrameStep = -1;
                }
                else
                {
                    Sprite.FrameStep = +1;
                }
                // Force direction to face wall
                if (left != null)
                {
                    Sprite.Direction = -1;
                }
                if (right != null)
                {
                    Sprite.Direction = +1;
                }
                if (Velocity.Y == 0 || !Controller.Climb)
                {
                    Sprite.Reset();
                }
                break;

            case PlayerState.Hiding:
                Sprite.Play("hide");
                if (Sprite.Frame == 34)
                {
                    MakeSound(chunk, "hide", 5);
                }
                break;

            case PlayerState.OpeningDoor:
                Sprite.Play("open");
                break;

            case PlayerState.CrashDoor:
                Sprite.Play("crash");
                break;

            case PlayerState.Dying:
                Sprite.Play("die");
                break;
            }

            if (StopSoundLoop)
            {
                StopSound();
            }

            // Base direction on movement
            if (Velocity.X < 0)
            {
                Sprite.Direction = -1;
            }
            if (0 < Velocity.X)
            {
                Sprite.Direction = +1;
            }

            Game.SoundEngine.Update(Position);
        }