public static MarioState PerformButtSlide(MarioState marioState, int angleDiff, TriangleDataModel floor, List <TriangleDataModel> walls)
        {
            MutableMarioState mutableMarioState = marioState.GetMutableMarioState(angleDiff);

            common_slide_action_with_jump(mutableMarioState, floor, walls);
            return(mutableMarioState.GetMarioState(marioState, new Input(angleDiff, 0)));
        }
 // perform_ground_step
 private static void PerformGroundStep(MutableMarioState marioState)
 {
     for (int i = 0; i < 4; i++)
     {
         marioState.X = marioState.X + marioState.XSpeed / 4.0f;
         marioState.Z = marioState.Z + marioState.ZSpeed / 4.0f;
     }
 }
        public static MarioState ApplyInput(MarioState initialState, int angleDiff)
        {
            MutableMarioState mutableMarioState = initialState.GetMutableMarioState(angleDiff);

            mutableMarioState.IntendedMagnitude *= 0.4f;
            UpdateWalkingSpeed(mutableMarioState);
            PerformGroundStep(mutableMarioState);
            MarioState finalState = mutableMarioState.GetMarioState(initialState, null);

            return(finalState);
        }
 private static void perform_ground_step(
     MutableMarioState marioState, TriangleDataModel floor, List <TriangleDataModel> walls)
 {
     for (int i = 0; i < 4; i++)
     {
         float intendedPosX = marioState.X + floor.NormY * (marioState.XSpeed / 4.0f);
         float intendedPosZ = marioState.Z + floor.NormY * (marioState.ZSpeed / 4.0f);
         float intendedPosY = marioState.Y;
         perform_ground_quarter_step(
             marioState, intendedPosX, intendedPosY, intendedPosZ, floor, walls);
     }
 }
        private static void perform_ground_quarter_step(
            MutableMarioState marioState, float intendedPosX, float intendedPosY, float intendedPosZ,
            TriangleDataModel floor, List <TriangleDataModel> walls)
        {
            (intendedPosX, intendedPosZ) =
                WallDisplacementCalculator.HandleWallDisplacement(
                    intendedPosX, intendedPosY, intendedPosZ, walls, 50, 60);

            float floorHeight = floor.GetTruncatedHeightOnTriangle(intendedPosX, intendedPosZ);

            marioState.X = intendedPosX;
            marioState.Y = floorHeight;
            marioState.Z = intendedPosZ;
        }
        // update_walking_speed
        private static void UpdateWalkingSpeed(MutableMarioState marioState)
        {
            float maxTargetSpeed;
            float targetSpeed;

            bool slowSurface = false;

            if (slowSurface)
            {
                maxTargetSpeed = 24.0f;
            }
            else
            {
                maxTargetSpeed = 32.0f;
            }

            targetSpeed = marioState.IntendedMagnitude < maxTargetSpeed ? marioState.IntendedMagnitude : maxTargetSpeed;

            if (marioState.HSpeed <= 0.0f)
            {
                marioState.HSpeed += 1.1f;
            }
            else if (marioState.HSpeed <= targetSpeed)
            {
                marioState.HSpeed += 1.1f - marioState.HSpeed / 43.0f;
            }
            else
            {
                marioState.HSpeed -= 1.0f;
            }

            if (marioState.HSpeed > 48.0f)
            {
                marioState.HSpeed = 48.0f;
            }

            marioState.MarioAngle = MoreMath.NormalizeAngleUshort(
                marioState.IntendedAngle - CalculatorUtilities.ApproachInt(
                    MoreMath.NormalizeAngleShort(marioState.IntendedAngle - marioState.MarioAngle), 0, 0x800, 0x800));
            ApplySlopeAccel(marioState);
        }
 // apply_slope_accel
 private static void ApplySlopeAccel(MutableMarioState marioState)
 {
     marioState.XSpeed = marioState.HSpeed * InGameTrigUtilities.InGameSine(marioState.MarioAngle);
     marioState.YSpeed = 0.0f;
     marioState.ZSpeed = marioState.HSpeed * InGameTrigUtilities.InGameCosine(marioState.MarioAngle);
 }
 private static void common_slide_action(
     MutableMarioState marioState, TriangleDataModel floor, List <TriangleDataModel> walls)
 {
     perform_ground_step(marioState, floor, walls);
     // TODO: confirm that result doesn't matter
 }
        private static void update_sliding_angle(MutableMarioState marioState, float accel, float lossFactor, TriangleDataModel floor, List <TriangleDataModel> walls)
        {
            short slopeAngle = MoreMath.NormalizeAngleShort(InGameTrigUtilities.InGameATan(floor.NormZ, floor.NormX));
            float steepness  = (float)Math.Sqrt(floor.NormX * floor.NormX + floor.NormZ * floor.NormZ);

            marioState.SlidingSpeedX += accel * steepness * InGameTrigUtilities.InGameSine(slopeAngle);
            marioState.SlidingSpeedZ += accel * steepness * InGameTrigUtilities.InGameCosine(slopeAngle);

            marioState.SlidingSpeedX *= lossFactor;
            marioState.SlidingSpeedZ *= lossFactor;

            marioState.SlidingAngle = InGameTrigUtilities.InGameATan(marioState.SlidingSpeedZ, marioState.SlidingSpeedX);

            short facingDYaw    = MoreMath.NormalizeAngleShort(marioState.MarioAngle - marioState.SlidingAngle);
            int   newFacingDYaw = facingDYaw;

            //! -0x4000 not handled - can slide down a slope while facing perpendicular to it
            if (newFacingDYaw > 0 && newFacingDYaw <= 0x4000)
            {
                if ((newFacingDYaw -= 0x200) < 0)
                {
                    newFacingDYaw = 0;
                }
            }
            else if (newFacingDYaw > -0x4000 && newFacingDYaw < 0)
            {
                if ((newFacingDYaw += 0x200) > 0)
                {
                    newFacingDYaw = 0;
                }
            }
            else if (newFacingDYaw > 0x4000 && newFacingDYaw < 0x8000)
            {
                if ((newFacingDYaw += 0x200) > 0x8000)
                {
                    newFacingDYaw = 0x8000;
                }
            }
            else if (newFacingDYaw > -0x8000 && newFacingDYaw < -0x4000)
            {
                if ((newFacingDYaw -= 0x200) < -0x8000)
                {
                    newFacingDYaw = -0x8000;
                }
            }

            marioState.MarioAngle = MoreMath.NormalizeAngleUshort(marioState.SlidingAngle + newFacingDYaw);

            marioState.XSpeed = marioState.SlidingSpeedX;
            marioState.YSpeed = 0.0f;
            marioState.ZSpeed = marioState.SlidingSpeedZ;

            //! Speed is capped a frame late (butt slide HSG)
            marioState.HSpeed = (float)Math.Sqrt(
                marioState.SlidingSpeedX * marioState.SlidingSpeedX +
                marioState.SlidingSpeedZ * marioState.SlidingSpeedZ);

            if (marioState.HSpeed > 100.0f)
            {
                marioState.SlidingSpeedX = marioState.SlidingSpeedX * 100.0f / marioState.HSpeed;
                marioState.SlidingSpeedZ = marioState.SlidingSpeedZ * 100.0f / marioState.HSpeed;
            }

            if (newFacingDYaw < -0x4000 || newFacingDYaw > 0x4000)
            {
                marioState.HSpeed *= -1.0f;
            }
        }
        private static void update_sliding(MutableMarioState marioState, float stopSpeed, TriangleDataModel floor, List <TriangleDataModel> walls)
        {
            short intendedDYaw = MoreMath.NormalizeAngleShort(marioState.IntendedAngle - marioState.SlidingAngle);
            float forward      = InGameTrigUtilities.InGameCosine(intendedDYaw);
            float sideward     = InGameTrigUtilities.InGameSine(intendedDYaw);

            //! 10k glitch
            if (forward < 0.0f && marioState.HSpeed >= 0.0f)
            {
                forward *= 0.5f + 0.5f * marioState.HSpeed / 100.0f;
            }

            float accel;
            float lossFactor;
            int   floorClass = 0x13;

            switch (floorClass)
            {
            case 0x0013:
                accel      = 10.0f;
                lossFactor = marioState.IntendedMagnitude / 32.0f * forward * 0.02f + 0.98f;
                break;

            case 0x0014:
                accel      = 8.0f;
                lossFactor = marioState.IntendedMagnitude / 32.0f * forward * 0.02f + 0.96f;
                break;

            default:
                accel      = 7.0f;
                lossFactor = marioState.IntendedMagnitude / 32.0f * forward * 0.02f + 0.92f;
                break;

            case 0x0015:
                accel      = 5.0f;
                lossFactor = marioState.IntendedMagnitude / 32.0f * forward * 0.02f + 0.92f;
                break;
            }

            float oldSpeed = (float)Math.Sqrt(
                marioState.SlidingSpeedX * marioState.SlidingSpeedX +
                marioState.SlidingSpeedZ * marioState.SlidingSpeedZ);

            //! This is attempting to use trig derivatives to rotate mario's speed.
            // It is slightly off/asymmetric since it uses the new X speed, but the old
            // Z speed.
            marioState.SlidingSpeedX += marioState.SlidingSpeedZ * (marioState.IntendedMagnitude / 32.0f) * sideward * 0.05f;
            marioState.SlidingSpeedZ -= marioState.SlidingSpeedX * (marioState.IntendedMagnitude / 32.0f) * sideward * 0.05f;

            float newSpeed = (float)Math.Sqrt(
                marioState.SlidingSpeedX * marioState.SlidingSpeedX +
                marioState.SlidingSpeedZ * marioState.SlidingSpeedZ);

            if (oldSpeed > 0.0f && newSpeed > 0.0f)
            {
                marioState.SlidingSpeedX = marioState.SlidingSpeedX * oldSpeed / newSpeed;
                marioState.SlidingSpeedZ = marioState.SlidingSpeedZ * oldSpeed / newSpeed;
            }

            update_sliding_angle(marioState, accel, lossFactor, floor, walls);
        }
 private static void common_slide_action_with_jump(MutableMarioState marioState, TriangleDataModel floor, List <TriangleDataModel> walls)
 {
     update_sliding(marioState, 4.0f, floor, walls);
     common_slide_action(marioState, floor, walls);
 }