Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Beatmap countdown support is missing #20584

Open
peppy opened this issue Oct 5, 2022 Discussed in #20583 · 4 comments · May be fixed by #21009
Open

Beatmap countdown support is missing #20584

peppy opened this issue Oct 5, 2022 Discussed in #20583 · 4 comments · May be fixed by #21009

Comments

@peppy
Copy link
Member

peppy commented Oct 5, 2022

One of the remaining elements which is completely missing from the game.

Let me know if someone wants to take this on and I will provide the relevant stable code.

Discussed in #20583

Originally posted by toadsworth-jr October 5, 2022
Due to a severe lack for appropriate words, I'll let this video speak for itself.

super_strong_am_I_right_in_osu_.getmp3.pro.2.mp4

(Side note, some beatmaps actually included a countdown, such as Disco Prince)

@peppy peppy changed the title Add legacy beatmap countdown from stable Beatmap countdown support is missing Oct 5, 2022
@salmonslay
Copy link
Contributor

salmonslay commented Oct 17, 2022

I haven't really worked on lazer before but it's something I want to get into, so I'd like to try implementing this. I assume osu.Game\Screens\Play\ would be the appropriate directory to start out in?

edit: it seems like most of the countdown textures & audio clips aren't available in lazer (count(1/2/3).png, go.png & count(1/2/3)s.wav), how do I go about adding them?

@smoogipoo
Copy link
Contributor

You can find the skin resources here: http://m1.ppy.sh/assets/osu!Default%20Skin.zip

You'll only need the 2x versions, which you should PR to https://github.com/ppy/osu-resources

@salmonslay
Copy link
Contributor

@peppy could you send the stable code for this?

@frenzibyte
Copy link
Member

        private void InitializeCountdown()
        {
            double firstCircle = hitObjectManager.hitObjects[0].StartTime;

            double offset = AudioEngine.BeatOffsetAt(firstCircle);
            double beatLengthOriginal = AudioEngine.BeatLengthAt(firstCircle);
            if (beatLengthOriginal <= 0) beatLengthOriginal = AudioEngine.BeatLengthAt(0);
            if (beatLengthOriginal <= 0) return;

            double goTime = offset - 5;
            double beatLength = beatLengthOriginal;

            //If the bpm is too fast let's double the length just because it seems sensible.
            if (beatLength <= 333)
                beatLength *= 2;

            //Apply user customisations.
            if (beatmap.Countdown == Countdown.DoubleSpeed)
                beatLength /= 2;
            else if (beatmap.Countdown == Countdown.HalfSpeed)
                beatLength *= 2;

            // Push the countdown back by the mapper's countdown offset before any other adjustments.
            firstCircle -= beatLength * beatmap.CountdownOffset;

            //Skip back until we are at a good place.
            if (goTime >= firstCircle)
                while (goTime > firstCircle - beatLength)
                    goTime -= beatLength;

            int divisor = 1;

            while (goTime < firstCircle - beatLength / divisor)
            {
                goTime += beatLength;
                double beat = ((float)(goTime - offset) / beatLengthOriginal) % 4;
                if (beat > 1.5 &&
                    beat < 3.5)
                    divisor = 2;
                else
                    divisor = 1;
            }

            goTime -= beatLength;

            bool useCountdown = goTime - 4 * beatLength > 0;

            int goTimeInt = (int)goTime;
            int beatLengthInt = (int)beatLength;

            bool targetPractice = ModManager.CheckActive(Player.currentScore.EnabledMods, Mods.Target);

            if (targetPractice || (useCountdown && beatmap.Countdown != Countdown.Disabled && Ruleset.AllowCountdown))
            {
                SkipBoundary = goTimeInt - 6 * beatLengthInt;
                CountdownTime = goTimeInt - 3 * beatLengthInt;

                pSprite ready =
                    new pSprite(TextureManager.Load(@"ready"), Fields.Centre, Origins.Centre,
                        Clocks.Audio, new Vector2(0, 0), 0.91f, false,
                        Color.TransparentWhite);

                if (!targetPractice)
                    AudioEngine.SampleEvents.Add(new SampleCacheItem((int)(goTimeInt - 5.9 * beatLengthInt), AudioEngine.LoadSample(@"readys"), 100, false));

                ready.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - 6 * beatLengthInt, goTimeInt - 5 * beatLengthInt));
                if (!SkinManager.UseNewLayout)
                {
                    ready.Transformations.Add(new Transformation(TransformationType.Scale, 3, 1, goTimeInt - 6 * beatLengthInt, goTimeInt - 5 * beatLengthInt));
                    ready.Transformations.Add(new Transformation(TransformationType.Rotation, -0.4f, 0, goTimeInt - 6 * beatLengthInt, goTimeInt - 5 * beatLengthInt));
                }

                ready.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - 4 * beatLengthInt, goTimeInt - 3 * beatLengthInt));
                ready.Transformations.Add(
                    new Transformation(TransformationType.Scale, 1, SkinManager.UseNewLayout ? 1.2f : 1.8f, goTimeInt - 4 * beatLengthInt,
                        goTimeInt - 3 * beatLengthInt));

                pSprite count1 =
                    new pSprite(TextureManager.Load(@"count1"), Fields.Centre, Origins.Centre,
                        Clocks.Audio, new Vector2(0, 0), 0.88f, false,
                        Color.TransparentWhite);

                pSprite count3 =
                    new pSprite(TextureManager.Load(@"count3"), Fields.Centre, SkinManager.UseNewLayout ? Origins.Centre : Origins.CentreRight,
                        Clocks.Audio, SkinManager.UseNewLayout ? new Vector2(0, 0) : new Vector2(count1.Width / -6.8f, 0), 0.9f, false,
                        Color.TransparentWhite);
                pSprite count2 =
                    new pSprite(TextureManager.Load(@"count2"), Fields.Centre, SkinManager.UseNewLayout ? Origins.Centre : Origins.CentreLeft,
                        Clocks.Audio, SkinManager.UseNewLayout ? new Vector2(0, 0) : new Vector2(count1.Width / 6.8f, 0), 0.89f, false,
                        Color.TransparentWhite);
                pSprite go =
                    new pSprite(TextureManager.Load(@"go"), Fields.Centre, Origins.Centre,
                        Clocks.Audio, new Vector2(0, 0), 0.91f, false,
                        Color.TransparentWhite);

                if (!targetPractice)
                {
                    if (AudioEngine.LoadSample(@"count3s") != -1)
                    {
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 3 * beatLengthInt, AudioEngine.LoadSample(@"count3s"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 2 * beatLengthInt, AudioEngine.LoadSample(@"count2s"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 1 * beatLengthInt, AudioEngine.LoadSample(@"count1s"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt, AudioEngine.LoadSample(@"gos"), 100, false));
                    }
                    else
                    {
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 3 * beatLengthInt, AudioEngine.LoadSample(@"count"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 2 * beatLengthInt, AudioEngine.LoadSample(@"count"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt - 1 * beatLengthInt, AudioEngine.LoadSample(@"count"), 100, false));
                        AudioEngine.SampleEvents.Add(new SampleCacheItem(goTimeInt, AudioEngine.LoadSample(@"count"), 100, false));
                    }
                }

                count3.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - (int)(3.2 * beatLengthInt), goTimeInt - 3 * beatLengthInt));
                count2.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - (int)(2.2 * beatLengthInt), goTimeInt - 2 * beatLengthInt));
                count1.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - (int)(1.2 * beatLengthInt), goTimeInt - 1 * beatLengthInt));

                if (SkinManager.UseNewLayout)
                {
                    count3.Transformations.Add(new Transformation(TransformationType.Scale, 1.4f, 1, goTimeInt - (int)(3.2 * beatLengthInt), goTimeInt - 3 * beatLengthInt));
                    count2.Transformations.Add(new Transformation(TransformationType.Scale, 1.4f, 1, goTimeInt - (int)(2.2 * beatLengthInt), goTimeInt - 2 * beatLengthInt));
                    count1.Transformations.Add(new Transformation(TransformationType.Scale, 1.4f, 1, goTimeInt - (int)(1.2 * beatLengthInt), goTimeInt - 1 * beatLengthInt));

                    count3.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(2.2 * beatLengthInt), goTimeInt - (int)(2.0 * beatLengthInt)));
                    count2.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(1.2 * beatLengthInt), goTimeInt - (int)(1.0 * beatLengthInt)));
                    count1.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(0.2 * beatLengthInt), goTimeInt - (int)(0.0 * beatLengthInt)));
                }
                else
                {
                    count3.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(0.2 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt)));
                    count2.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(0.2 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt)));
                    count1.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt - (int)(0.2 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt)));
                }

                if (SkinManager.UseNewLayout)
                {
                    go.Transformations.Add(new Transformation(TransformationType.Scale, 1.4f, 1, goTimeInt - (int)(0.6 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt)));
                    go.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - (int)(0.2 * beatLengthInt), goTimeInt - 0 * beatLengthInt));
                }
                else
                {
                    go.Transformations.Add(new Transformation(TransformationType.Fade, 0, 1, goTimeInt - (int)(0.6 * beatLengthInt), goTimeInt));

                    Transformation t = new Transformation(TransformationType.Rotation, -4, 0, goTimeInt - (int)(0.6 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt));
                    t.Easing = EasingTypes.Out;
                    go.Transformations.Add(t);

                    t = new Transformation(TransformationType.Scale, 0.2f, 1, goTimeInt - (int)(0.6 * beatLengthInt), goTimeInt + (int)(0.2 * beatLengthInt));
                    t.Easing = EasingTypes.Out;
                    go.Transformations.Add(t);
                }

                go.Transformations.Add(new Transformation(TransformationType.Fade, 1, 0, goTimeInt + (int)(0.3 * beatLengthInt), goTimeInt + beatLengthInt));

                ready.DimImmune = true;
                count3.DimImmune = true;
                count2.DimImmune = true;
                count1.DimImmune = true;
                go.DimImmune = true;


                spriteManagerBelowHitObjectsWidescreen.Add(ready);
                spriteManagerBelowHitObjectsWidescreen.Add(count3);
                spriteManagerBelowHitObjectsWidescreen.Add(count2);
                spriteManagerBelowHitObjectsWidescreen.Add(count1);
                spriteManagerBelowHitObjectsWidescreen.Add(go);
            }
            else if (hitObjectManager.hitObjects[0].StartTime > 6000)
            {
                int loopStartTime = hitObjectManager.hitObjects[0].StartTime - hitObjectManager.PreEmpt - 900;
                int loopCount = ARROW_LOOP_COUNT + Math.Min(2, hitObjectManager.PreEmpt / 200);
                ApplyArrowTransformations(loopCount, loopStartTime);
            }
        }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants