diff --git a/osu.Android.props b/osu.Android.props index 83b17f0d87..0d3fafd19f 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs index fece3494e6..d7ebe9333d 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Default/MainCirclePiece.cs @@ -15,8 +15,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default { public class MainCirclePiece : CompositeDrawable { - public override bool RemoveCompletedTransforms => false; - private readonly CirclePiece circle; private readonly RingPiece ring; private readonly FlashPiece flash; @@ -44,7 +42,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default private readonly IBindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -56,7 +53,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); - armedState.BindTo(drawableObject.State); } protected override void LoadComplete() @@ -72,19 +68,18 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default indexInCurrentCombo.BindValueChanged(index => number.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(animate, true); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableObject, drawableObject.State.Value); } - private void animate(ValueChangedEvent state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { - ClearTransforms(true); - using (BeginAbsoluteSequence(drawableObject.StateUpdateTime)) glow.FadeOut(400); using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state.NewValue) + switch (state) { case ArmedState.Hit: const double flash_in = 40; @@ -111,5 +106,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Default } } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs index e5200ac248..7a210324d7 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyMainCirclePiece.cs @@ -41,7 +41,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy private readonly Bindable accentColour = new Bindable(); private readonly IBindable indexInCurrentCombo = new Bindable(); - private readonly IBindable armedState = new Bindable(); [Resolved] private DrawableHitObject drawableObject { get; set; } @@ -116,7 +115,6 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy accentColour.BindTo(drawableObject.AccentColour); indexInCurrentCombo.BindTo(drawableOsuObject.IndexInCurrentComboBindable); - armedState.BindTo(drawableObject.State); Texture getTextureWithFallback(string name) { @@ -142,18 +140,17 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy if (hasNumber) indexInCurrentCombo.BindValueChanged(index => hitCircleText.Text = (index.NewValue + 1).ToString(), true); - armedState.BindValueChanged(animate, true); + drawableObject.ApplyCustomUpdateState += updateStateTransforms; + updateStateTransforms(drawableObject, drawableObject.State.Value); } - private void animate(ValueChangedEvent state) + private void updateStateTransforms(DrawableHitObject drawableHitObject, ArmedState state) { const double legacy_fade_duration = 240; - ClearTransforms(true); - using (BeginAbsoluteSequence(drawableObject.HitStateUpdateTime)) { - switch (state.NewValue) + switch (state) { case ArmedState.Hit: circleSprites.FadeOut(legacy_fade_duration, Easing.Out); @@ -178,5 +175,13 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy } } } + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (drawableObject != null) + drawableObject.ApplyCustomUpdateState -= updateStateTransforms; + } } } diff --git a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs index 2a12577ad8..7accaef818 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestSceneHitErrorMeter.cs @@ -109,6 +109,34 @@ namespace osu.Game.Tests.Visual.Gameplay meter => meter.ChildrenOfType().Count() == 2)); } + [Test] + public void TestBonus() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + + AddStep("small bonus", () => newJudgement(result: HitResult.SmallBonus)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + + AddStep("large bonus", () => newJudgement(result: HitResult.LargeBonus)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + } + + [Test] + public void TestIgnore() + { + AddStep("OD 1", () => recreateDisplay(new OsuHitWindows(), 1)); + + AddStep("ignore hit", () => newJudgement(result: HitResult.IgnoreHit)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + + AddStep("ignore miss", () => newJudgement(result: HitResult.IgnoreMiss)); + AddAssert("no bars added", () => !this.ChildrenOfType().Any()); + AddAssert("no circle added", () => !this.ChildrenOfType().Any()); + } + private void recreateDisplay(HitWindows hitWindows, float overallDifficulty) { hitWindows?.SetDifficulty(overallDifficulty); diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs index 4d09ed21dc..3506d459ce 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiOverlay.cs @@ -30,7 +30,7 @@ namespace osu.Game.Tests.Visual.Online public void TestArticlePage() { setUpWikiResponse(responseArticlePage); - AddStep("Show Article Page", () => wiki.ShowPage("Interface")); + AddStep("Show Article Page", () => wiki.ShowPage("Article_styling_criteria/Formatting")); } [Test] @@ -69,16 +69,16 @@ namespace osu.Game.Tests.Visual.Online "---\nlayout: main_page\n---\n\n\n\n
\nWelcome to the osu! wiki, a project containing a wide range of osu! related information.\n
\n\n
\n
\n\n# Getting started\n\n[Welcome](/wiki/Welcome) • [Installation](/wiki/Installation) • [Registration](/wiki/Registration) • [Help Centre](/wiki/Help_Centre) • [FAQ](/wiki/FAQ)\n\n
\n
\n\n# Game client\n\n[Interface](/wiki/Interface) • [Options](/wiki/Options) • [Visual settings](/wiki/Visual_Settings) • [Shortcut key reference](/wiki/Shortcut_key_reference) • [Configuration file](/wiki/osu!_Program_Files/User_Configuration_File) • [Program files](/wiki/osu!_Program_Files)\n\n[File formats](/wiki/osu!_File_Formats): [.osz](/wiki/osu!_File_Formats/Osz_(file_format)) • [.osk](/wiki/osu!_File_Formats/Osk_(file_format)) • [.osr](/wiki/osu!_File_Formats/Osr_(file_format)) • [.osu](/wiki/osu!_File_Formats/Osu_(file_format)) • [.osb](/wiki/osu!_File_Formats/Osb_(file_format)) • [.db](/wiki/osu!_File_Formats/Db_(file_format))\n\n
\n
\n\n# Gameplay\n\n[Game modes](/wiki/Game_mode): [osu!](/wiki/Game_mode/osu!) • [osu!taiko](/wiki/Game_mode/osu!taiko) • [osu!catch](/wiki/Game_mode/osu!catch) • [osu!mania](/wiki/Game_mode/osu!mania)\n\n[Beatmap](/wiki/Beatmap) • [Hit object](/wiki/Hit_object) • [Mods](/wiki/Game_modifier) • [Score](/wiki/Score) • [Replay](/wiki/Replay) • [Multi](/wiki/Multi)\n\n
\n
\n\n# [Beatmap editor](/wiki/Beatmap_Editor)\n\nSections: [Compose](/wiki/Beatmap_Editor/Compose) • [Design](/wiki/Beatmap_Editor/Design) • [Timing](/wiki/Beatmap_Editor/Timing) • [Song setup](/wiki/Beatmap_Editor/Song_Setup)\n\nComponents: [AiMod](/wiki/Beatmap_Editor/AiMod) • [Beat snap divisor](/wiki/Beatmap_Editor/Beat_Snap_Divisor) • [Distance snap](/wiki/Beatmap_Editor/Distance_Snap) • [Menu](/wiki/Beatmap_Editor/Menu) • [SB load](/wiki/Beatmap_Editor/SB_Load) • [Timelines](/wiki/Beatmap_Editor/Timelines)\n\n[Beatmapping](/wiki/Beatmapping) • [Difficulty](/wiki/Beatmap/Difficulty) • [Mapping techniques](/wiki/Mapping_Techniques) • [Storyboarding](/wiki/Storyboarding)\n\n
\n
\n\n# Beatmap submission and ranking\n\n[Submission](/wiki/Submission) • [Modding](/wiki/Modding) • [Ranking procedure](/wiki/Beatmap_ranking_procedure) • [Mappers' Guild](/wiki/Mappers_Guild) • [Project Loved](/wiki/Project_Loved)\n\n[Ranking criteria](/wiki/Ranking_Criteria): [osu!](/wiki/Ranking_Criteria/osu!) • [osu!taiko](/wiki/Ranking_Criteria/osu!taiko) • [osu!catch](/wiki/Ranking_Criteria/osu!catch) • [osu!mania](/wiki/Ranking_Criteria/osu!mania)\n\n
\n
\n\n# Community\n\n[Tournaments](/wiki/Tournaments) • [Skinning](/wiki/Skinning) • [Projects](/wiki/Projects) • [Guides](/wiki/Guides) • [osu!dev Discord server](/wiki/osu!dev_Discord_server) • [How you can help](/wiki/How_You_Can_Help!) • [Glossary](/wiki/Glossary)\n\n
\n
\n\n# People\n\n[The Team](/wiki/People/The_Team): [Developers](/wiki/People/The_Team/Developers) • [Global Moderation Team](/wiki/People/The_Team/Global_Moderation_Team) • [Support Team](/wiki/People/The_Team/Support_Team) • [Nomination Assessment Team](/wiki/People/The_Team/Nomination_Assessment_Team) • [Beatmap Nominators](/wiki/People/The_Team/Beatmap_Nominators) • [osu! Alumni](/wiki/People/The_Team/osu!_Alumni) • [Project Loved Team](/wiki/People/The_Team/Project_Loved_Team)\n\nOrganisations: [osu! UCI](/wiki/Organisations/osu!_UCI)\n\n[Community Contributors](/wiki/People/Community_Contributors) • [Users with unique titles](/wiki/People/Users_with_unique_titles)\n\n
\n
\n\n# For developers\n\n[API](/wiki/osu!api) • [Bot account](/wiki/Bot_account) • [Brand identity guidelines](/wiki/Brand_identity_guidelines)\n\n
\n
\n\n# About the wiki\n\n[Sitemap](/wiki/Sitemap) • [Contribution guide](/wiki/osu!_wiki_Contribution_Guide) • [Article styling criteria](/wiki/Article_Styling_Criteria) • [News styling criteria](/wiki/News_Styling_Criteria)\n\n
\n
\n", }; - // From https://osu.ppy.sh/api/v2/wiki/en/Interface + // From https://osu.ppy.sh/api/v2/wiki/en/Article_styling_criteria/Formatting private APIWikiPage responseArticlePage => new APIWikiPage { - Title = "Interface", + Title = "Formatting", Layout = "markdown_page", - Path = "Interface", + Path = "Article_styling_criteria/Formatting", Locale = "en", - Subtitle = null, + Subtitle = "Article styling criteria", Markdown = - "# Interface\n\n![](img/intro-screen.jpg \"Introduction screen\")\n\n## Main Menu\n\n![](img/main-menu.jpg \"Main Menu\")\n\nThe [osu!cookie](/wiki/Glossary#cookie) \\[1\\] pulses according to the [BPM](/wiki/Beatmapping/Beats_per_minute) of any song currently playing on the main menu. In addition, bars will extend out of the osu!cookie in accordance to the song's volume. If no song is playing, it pulses at a slow 60 BPM. The elements of the main menu are as follows:\n\n- \\[2\\] Click Play (`P`) or the logo to switch to the Solo mode song selection screen.\n- \\[3\\] Click Edit (`E`) to open the Editor mode song selection screen.\n- \\[4\\] Click Options (`O`) to go to the Options screen.\n- \\[5\\] Click Exit (`Esc`) to exit osu!.\n- \\[6\\] A random useful tip is displayed below the menu.\n- \\[7\\] In the lower-left is a link to the osu! website, as well as copyright information.\n- \\[8\\] Connection result to [Bancho](/wiki/Glossary#bancho)! In this picture it is not shown, but the connection result looks like a chain link.\n- \\[9\\] In the bottom right are the chat controls for the extended [chat window](/wiki/Chat_Console) (called \"Player List\" here) and the regular chat window (`F9` & `F8`, respectively).\n- \\[10\\] In the upper right is the osu! jukebox which plays the songs in random order. The top shows the song currently playing. The buttons, from left to right, do as follows:\n - Previous Track\n - Play\n - Pause\n - Stop (the difference between Play and Stop is that Stop will reset the song to the beginning, while Pause simply pauses it)\n - Next Track\n - View Song Info. This toggles the top bar showing the song info between being permanent and temporary. When permanent, the info bar will stay visible until it fades out with the rest of the UI. When temporary, it will disappear a little while after a song has been chosen. It will stay hidden until it is toggled again, or another song plays.\n- \\[11\\] The number of beatmaps you have available, how long your osu!client has been running, and your system clock.\n- \\[12\\] Your profile, click on it to display the User Options (see below).\n\n## User Options\n\n![](img/user-options.jpg \"User Options\")\n\nAccess this screen by clicking your profile at the top left of the main menu. You cannot access the Chat Consoles while viewing the user option screen. You can select any item by pressing the corresponding number on the option:\n\n1. `View Profile`: Opens up your profile page in your default web browser.\n2. `Sign Out`: Sign out of your account (after signing out, the [Options](/wiki/Options) sidebar will prompt you to sign in).\n3. `Change Avatar`: Open up the edit avatar page in your default web browser.\n4. `Close`: Close this dialog\n\n## Play Menu\n\n![](img/play-menu.jpg \"Play Menu\")\n\n- Click `Solo` (`P`) to play alone.\n- Click `Multi` (`M`) to play with other people. You will be directed to the [Multi](/wiki/Multi) Lobby (see below).\n- Click `Back` to return to the main menu.\n\n## Multi Lobby\n\n*Main page: [Multi](/wiki/Multi)*\n\n![](img/multi-lobby.jpg \"Multi Lobby\")\n\n![](img/multi-room.jpg \"Multi Host\")\n\n1. Your rank in the match. This is also shown next to your name.\n2. Your profile information.\n3. The jukebox.\n4. Player list - displays player names, their rank (host or player), their [mods](/wiki/Game_modifier) activated (if any, see \\#7), their osu! ranking, and their team (if applicable).\n5. The name of the match and the password settings.\n6. The beatmap selected. It shows the beatmap as it would in the solo song selection screen.\n7. The [mods](/wiki/Game_modifier) that you have activated (see #12), as well as the option to select them. The option marked \"Free Mods\" toggles whether or not players can select their own mods. If yes, they can pick any combination of mods *except for speed-altering mods like [Double Time](/wiki/Game_modifier/Double_Time)*. If no, the host decides what mods will be used. The host can pick speed-altering mods regardless of whether or not Free Mods is turned on.\n8. The team mode and win conditions.\n9. The ready button.\n10. The [chat console](/wiki/Chat_Console).\n11. The leave button.\n12. Where your activated mods appear.\n\n## Song Selection Screen\n\n![](img/song-selection.jpg \"Song Selection\")\n\nYou can identify the current mode selected by either looking at the icon in the bottom left, above Mode, or by looking at the transparent icon in the center of the screen. These are the four you will see:\n\n- ![](/wiki/shared/mode/osu.png) is [osu!](/wiki/Game_mode/osu!)\n- ![](/wiki/shared/mode/taiko.png) is [osu!taiko](/wiki/Game_mode/osu!taiko)\n- ![](/wiki/shared/mode/catch.png) is [osu!catch](/wiki/Game_mode/osu!catch)\n- ![](/wiki/shared/mode/mania.png) is [osu!mania](/wiki/Game_mode/osu!mania)\n\nBefore continuing on, this screen has too many elements to note with easily, noticeable numbers. The subsections below will focus on one part of the screen at a time, starting from the top down and left to right.\n\n### Beatmap Information\n\n![](img/metadata-comparison.jpg)\n\n![](img/beatmap-metadata.jpg)\n\nThis area displays **information on the beatmap difficulty currently selected.** By default, the beatmap whose song is heard in the osu! jukebox is selected when entering the selection screen. In the top left is the ranked status of the beatmap. The title is next. Normally, the romanised title is shown, but if you select `Prefer metadata in original language` in the [Options](/wiki/Options), it will show the Unicode title; this is shown in the upper picture. The beatmapper is also shown, and beatmap information is shown below. From left to right, the values are as follows:\n\n- **Length**: The total length of the beatmap, from start to finish and including breaks. Not to be confused with [drain time](/wiki/Glossary#drain-time).\n- **BPM**: The BPM of the beatmap. If (like in the lower picture) there are two BPMS and one in parentheses, this means that the BPM changes throughout the song. It shows the slowest and fastest BPMs, and the value in parentheses is the BPM at the start of the beatmap.\n- **Objects**: The total amount of [hit objects](/wiki/Hit_Objects) in the beatmap.\n- **Circles**: The total amount of hit circles in the beatmap.\n- **Sliders**: The total amount of sliders in the beatmap.\n- **Spinners**: The total amount of spinners in the beatmap.\n- **OD**: The Overall Difficulty of the beatmap.\n- **HP**: The drain rate of your HP. In osu!, this is how much of an HP loss you receive upon missing a note, how fast the life bar idly drains, and how much HP is received for hitting a note. In osu!mania, this is the same except there is no idle HP drain. In osu!taiko, this determines how slowly the HP bar fills and how much HP is lost when a note is missed. osu!catch is the same as osu!.\n- **Stars**: The star difficulty of the beatmap. This is graphically visible in the beatmap rectangle itself.\n\n### Group and Sort\n\n![](img/beatmap-filters.jpg)\n\nClick on one of the tabs to **sort your song list according to the selected criterion**.\n\n**Group** - Most options organize beatmaps into various expandable groups:\n\n- `No grouping` - Beatmaps will not be grouped but will still be sorted in the order specified by Sort.\n- `By Difficulty` - Beatmaps will be grouped by their star difficulty, rounded to the nearest whole number.\n- `By Artist` - Beatmaps will be grouped by the artist's first character of their name.\n- `Recently Played` - Beatmaps will be grouped by when you last played them.\n- `Collections` - This will show the collections you have created. *Note that this will hide beatmaps not listed in a collection!*\n- `By BPM` - Beatmaps will be grouped according to BPM in multiples of 60, starting at 120.\n- `By Creator` - Beatmaps will be grouped by the beatmap creator's name's first character.\n- `By Date Added` - Beatmaps will be grouped according to when they were added, from today to 4+ months ago.\n- `By Length` - Beatmaps will be grouped according to their length: 1 minute or less, 2 minutes or less, 3, 4, 5, and 10.\n- `By Mode` - Beatmaps will be grouped according to their game mode.\n- `By Rank Achieved` - Beatmaps will be sorted by the highest rank achieved on them.\n- `By Title` - Beatmaps will be grouped by the first letter of their title.\n- `Favourites` - Only beatmaps you have favorited online will be shown.\n- `My Maps` - Only beatmaps you have mapped (that is, whose creator matches your profile name) will be shown.\n- `Ranked Status` - Beatmaps will be grouped by their ranked status: ranked, pending, not submitted, unknown, or loved.\n\nThe first five groupings are available in tabs below Group and Sort.\n\n**Sort** - Sorts beatmaps in a certain order\n\n- `By Artist` - Beatmaps will be sorted alphabetically by the artist's name's first character.\n- `By BPM` - Beatmaps will be sorted lowest to highest by their BPM. For maps with multiple BPMs, the highest will be used.\n- `By Creator` - Beatmaps will be sorted alphabetically by the creator's name's first character.\n- `By Date Added` - Beatmaps will be sorted from oldest to newest by when they were added.\n- `By Difficulty` - Beatmaps will be sorted from easiest to hardest by star difficulty. *Note that this will split apart mapsets!*\n- `By Length` - Beatmaps will be sorted from shortest to longest by length.\n- `By Rank Achieved` - Beatmaps will be sorted from poorest to best by the highest rank achieved on them.\n- `By Title` - Beatmaps will be sorted alphabetically by the first character of their name.\n\n### Search\n\n![](img/search-bar.jpg)\n\n*Note: You cannot have the chat console or the options sidebar open if you want to search; otherwise, anything you type will be perceived as chat text or as an options search query.*\n\nOnly beatmaps that match the criteria of your search will be shown. By default, any search will be matched against the beatmaps' artists, titles, creators, and tags.\n\nIn addition to searching these fields, you can use filters to search through other metadata by combining one of the supported filters with a comparison to a value (for example, `ar=9`).\n\nSupported filters:\n\n- `artist`: Name of the artist\n- `creator`: Name of the beatmap creator\n- `ar`: Approach Rate\n- `cs`: Circle Size\n- `od`: Overall Difficulty\n- `hp`: HP Drain Rate\n- `keys`: Number of keys (osu!mania and converted beatmaps only)\n- `stars`: Star Difficulty\n- `bpm`: Beats per minute\n- `length`: Length in seconds\n- `drain`: Drain Time in seconds\n- `mode`: Mode. Value can be `osu`, `taiko`, `catchthebeat`, or `mania`, or `o`/`t`/`c`/`m` for short.\n- `status`: Ranked status. Value can be `ranked`, `approved`, `pending`, `notsubmitted`, `unknown`, or `loved`, or `r`/`a`/`p`/`n`/`u`/`l` for short.\n- `played`: Time since last played in days\n- `unplayed`: Shows only unplayed maps. A comparison with no set value must be used. The comparison itself is ignored.\n- `speed`: Saved osu!mania scroll speed. Always 0 for unplayed maps or if the [Remember osu!mania scroll speed per beatmap](/wiki/Options#gameplay) option is off\n\nSupported comparisons:\n\n- `=` or `==`: Equal to\n- `!=`: Not equal to\n- `<`: Less than\n- `>`: Greater than\n- `<=`: Less than or equal to\n- `>=`: Greater than or equal to\n\nYou may also enter a beatmap or beatmapset ID in your search to get a single result.\n\n### Rankings\n\n![](img/leaderboards.jpg)\n\n A variety of things can appear in this space:\n\n- A \"Not Submitted\" box denotes a beatmap that has not been uploaded to the osu! site using the Beatmap Submission System or was deleted by the mapper.\n- An \"Update to latest version\" box appears if there is a new version of the beatmap available for download. Click on the button to update.\n - **Note:** Once you update the beatmap, it cannot be reversed. If you want to preserve the older version for some reason (say, to keep scores), then do not update.\n- A \"Latest pending version\" box appears means that the beatmap has been uploaded to the osu!website but is not ranked yet.\n- If replays matching the view setting of the beatmap exist, they will be displayed instead of a box denoting the ranked/played status of the beatmap. This is shown in the above picture.\n - Under public rankings (e.g. Global, Friends, etc.), your high score will be shown at the bottom, as well as your rank on the leaderboard.\n- A \"No records set!\" box means that there are no replays for the current view setting (this is typically seen in the Local view setting if you just downloaded or edited the beatmap).\n - Note: Scores for Multi are not counted as records.\n\nThese are the view settings:\n\n- Local Ranking\n- Country Ranking\\*\n- Global Ranking\n- Global Ranking (Selected Mods)\\*\n- Friend Ranking\\*\n\n\\*Requires you to be an [osu!supporter](/wiki/osu!supporter) to access them.\n\nClick the word bubble icon to call up the **Quick Web Access** screen for the selected beatmap:\n\n- Press `1` or click the `Beatmap Listing/Scores` button and your default internet browser will pull up the Beatmap Listing and score page of the beatmap set the selected beatmap belongs to.\n- Press `2` or click `Beatmap Modding` and your default internet browser will pull up the modding page of the beatmap set the selected beatmap belongs to.\n- Press `3` or `Esc` or click `Cancel` to return to the Song Selection Screen.\n\nWhile you are on the Quick Web Access Screen, you cannot access the Chat and Extended Chat Consoles.\n\n### Song\n\n![](img/beatmap-cards.jpg)\n\nThe song list displays all available beatmaps. Different beatmaps may have different coloured boxes:\n\n- **Pink**: This beatmap has not been played yet.\n- **Orange**: At least one beatmap from the beatmapset has been completed.\n- **Light Blue**: Other beatmaps in the same set, shown when a mapset is expanded.\n- **White**: Currently selected beatmap.\n\nYou can navigate the beatmap list by using the mouse wheel, using the up and down arrow keys, dragging it while holding the left mouse button or clicking the right mouse button (previously known as Absolute Scrolling), which will move the scroll bar to your mouse's Y position. Click on a box to select that beatmap and display its information on the upper left, high scores (if any) on the left and, if you've cleared it, the letter grade of the highest score you've achieved. Click the box again, press `Enter` or click the osu!cookie at the lower right to begin playing the beatmap.\n\n### Gameplay toolbox\n\n![](img/game-mode-selector.jpg \"List of available game modes\")\n\n![](img/gameplay-toolbox.jpg)\n\nThis section can be called the gameplay toolbox. We will cover each button's use from left to right.\n\nPress `Esc` or click the `Back` button to return to main menu.\n\nClick on the `Mode` button to open up a list of gameplay modes available on osu!. Click on your desired gameplay mode and osu! will switch to that gameplay mode style - the scoreboard will change accordingly. Alternatively, you can press `Ctrl` and `1` (osu!), `2` (osu!taiko), `3` (osu!catch), or `4` (osu!mania) to change the gamemode.\n\nThe background transparent icon and the \"Mode\" box will change to depict what mode is currently selected.\n\n![](img/game-modifiers.jpg \"Mod Selection Screen\")\n\nClick the `Mods` button or press `F1` to open the **[Mod Selection Screen](/wiki/Game_modifier)**.\n\nIn this screen, you can apply modifications (\"mods\" for short) to gameplay. Some mods lower difficulty and apply a multiplier that lowers the score you achieve. Conversely, some mods increase the difficulty, but apply a multiplier that increases the score you achieve. Finally, some mods modify gameplay in a different way. [Relax](/wiki/Game_modifier/Relax) and [Auto Pilot](/wiki/Game_modifier/Autopilot) fall in that category.\n\nPlace your mouse on a mod's icon to see a short description of its effect. Click on an icon to select or deselect that mod. Some mods, like Double Time, have multiple variations; click on the mod again to cycle through. The score multiplier value displays the combined effect the multipliers of the mod(s) of you have selected will have on your score. Click `Reset all mods` or press `1` to deselect all currently selected mods. Click `Close` or press `2` or `Esc` to return to the Song Selection Screen.\n\nWhile you are on the Mod Selection Screen, you cannot access the Chat and Extended Chat Consoles. In addition, skins can alter the text and/or icon of the mods, but the effects will still be the same.\n\nClick the `Random` button or press `F2` to have the game **randomly scroll through all of your beatmaps and pick one.** You cannot select a beatmap yourself until it has finished scrolling.\n\n*Note: You can press `Shift` + the `Random` button or `F2` to go back to the beatmap you had selected before you randomized your selection.*\n\n![](img/beatmap-options.jpg \"Possible commands for a beatmap\")\n\nClick the `Beatmap Options` button, press `F3` or right-click your mouse while hovering over the beatmap to call up the **Beatmap Options Menu for options on the currently selected beatmap**.\n\n- Press `1` or click the `Manage Collections` button to bring up the Collections screen - here, you can manage pre-existing collections, as well as add or remove the currently selected beatmap or mapset to or from a collection.\n- Press `2` or click `Delete...` to delete the \\[1\\] currently selected beatmapset, \\[2\\] delete the currently selected beatmap, or \\[3\\] delete **all VISIBLE beatmaps**.\n - Note that deleted beatmaps are moved to the Recycle Bin.\n- Press `3` or click `Remove from Unplayed` to mark an unplayed beatmap as played (that is, change its box colour from pink to orange).\n- Press `4` or click `Clear local scores` to delete all records of the scores you have achieved in this beatmap.\n- Press `5` or click `Edit` to open the selected beatmap in osu!'s Editor.\n- Press `6` or `Esc` or click `Close` to return to the Song Selection Screen.\n\nClick on **your user panel** to access the **User Options Menu**.\n\nClick the **[osu!cookie](/wiki/Glossary#cookie)** to **start playing the selected beatmap**.\n\n## Results screen\n\n![](img/results-osu.jpg \"Accuracy in osu!\")\n\nThis is the results screen shown after you have successfully passed the beatmap. You can access your online results by scrolling down or pressing the obvious button.\n\n**Note:** The results screen may change depending on the used skin.\n\nBelow are the results screens of the other game modes.\n\n![](img/results-taiko.jpg \"Accuracy in osu!taiko\")\n\n![](img/results-mania.jpg \"Accuracy in osu!mania\")\n\n![](img/results-catch.jpg \"Accuracy in osu!catch\")\n\n### Online Leaderboard\n\n![](img/extended-results-screen.jpg \"An example of an osu!online score\")\n\nThis is your online leaderboard. You can go here by scrolling down from the results screen. Your Local Scoreboard will show your name and the score as usual.\n\n1. Your player bar. It shows your [PP](/wiki/Performance_Points), Global Rank, Total Score, Overall [Accuracy](/wiki/Accuracy), and level bar.\n2. `Save replay to Replays folder`: You can watch the replay later either by opening it from a local leaderboard, or by going to `Replays` directory and double clicking it.\n3. `Add as online favourite`: Include the beatmap into your list of favourites, which is located on your osu! profile page under the \"Beatmaps\" section.\n4. Local Leaderboard: All your results are stored on your computer. To see them, navigate to the [song selection screen](#song-selection-screen), then select `Local Rankings` from the drop-down menu on the left.\n5. `Beatmap Ranking` section. Available only for maps with online leaderboards ([qualified](/wiki/Beatmap/Category#qualified), [ranked](/wiki/Beatmap/Category#ranked), or [loved](/wiki/Beatmap/Category#loved)). You also need to be online to see this section.\n 1. `Overall`: Your position on the map's leaderboard, where you compete against players that used [mods](/wiki/Game_modifier), even if you didn't use any yourself.\n 2. `Accuracy`: How [precisely](/wiki/Accuracy) did you play the beatmap. Will only be counted when your old score is surpassed.\n 3. `Max Combo`: Your longest combo on the map you played.\n 4. `Ranked Score`: Your [best result](/wiki/Score#ranked-score) on the beatmap.\n 5. `Total Score`: Not taken into account, since it does not affect your position in online rankings.\n 6. `Performance`: The amount of [unweighted PP](/wiki/Performance_points#why-didnt-i-gain-the-full-amount-of-pp-from-a-map-i-played) you would receive for the play.\n6. `Overall Ranking` section. It's available only for beatmaps with online leaderboards. You also need to be online to see this section.\n 1. `Overall`: Your global ranking in the world.\n 2. `Accuracy`: Your average [accuracy](/wiki/Accuracy#accuracy) over all beatmaps you have played.\n 3. `Max Combo`: The longest combo over all beatmaps you have played.\n 4. [`Ranked Score`](/wiki/Score#ranked-score): The number of points earned from all ranked beatmaps that you have ever played, with every map being counted exactly once.\n 5. [`Total Score`](/wiki/Score#total-score): Same as ranked score, but it takes into account all beatmaps available on the osu! website, and also underplayed or failed beatmaps. This counts towards your level.\n 6. `Perfomance`: Displays your total amount of Performance Points, and also how many PP the submitted play was worth.\n7. Information about the beatmap with its playcount and pass rate.\n8. Beatmap rating. Use your personal discretion based on whether you enjoy the beatmap or not. Best left alone if you can't decide.\n9. Click here to return to the song selection screen.\n\n![](img/medal-unlock.jpg \"Unlocking a medal\")\n\nAbove is what it looks like to receive a medal.\n", + "# Formatting\n\n*For the writing standards, see: [Article style criteria/Writing](../Writing)*\n\n*Notice: This article uses [RFC 2119](https://tools.ietf.org/html/rfc2119 \"IETF Tools\") to describe requirement levels.*\n\n## Locales\n\nListed below are the properly-supported locales for the wiki:\n\n| File Name | Locale Name | Native Script |\n| :-- | :-- | :-- |\n| `en.md` | English | English |\n| `ar.md` | Arabic | اَلْعَرَبِيَّةُ |\n| `be.md` | Belarusian | Беларуская мова |\n| `bg.md` | Bulgarian | Български |\n| `cs.md` | Czech | Česky |\n| `da.md` | Danish | Dansk |\n| `de.md` | German | Deutsch |\n| `gr.md` | Greek | Ελληνικά |\n| `es.md` | Spanish | Español |\n| `fi.md` | Finnish | Suomi |\n| `fr.md` | French | Français |\n| `hu.md` | Hungarian | Magyar |\n| `id.md` | Indonesian | Bahasa Indonesia |\n| `it.md` | Italian | Italiano |\n| `ja.md` | Japanese | 日本語 |\n| `ko.md` | Korean | 한국어 |\n| `nl.md` | Dutch | Nederlands |\n| `no.md` | Norwegian | Norsk |\n| `pl.md` | Polish | Polski |\n| `pt.md` | Portuguese | Português |\n| `pt-br.md` | Brazilian Portuguese | Português (Brasil) |\n| `ro.md` | Romanian | Română |\n| `ru.md` | Russian | Русский |\n| `sk.md` | Slovak | Slovenčina |\n| `sv.md` | Swedish | Svenska |\n| `th.md` | Thai | ไทย |\n| `tr.md` | Turkish | Türkçe |\n| `uk.md` | Ukrainian | Українська мова |\n| `vi.md` | Vietnamese | Tiếng Việt |\n| `zh.md` | Chinese (Simplified) | 简体中文 |\n| `zh-tw.md` | Traditional Chinese (Taiwan) | 繁體中文(台灣) |\n\n*Note: The website will give readers their selected language's version of an article. If it is not available, the English version will be given.*\n\n### Content parity\n\nTranslations are subject to strict content parity with their English article, in the sense that they must have the same message, regardless of grammar and syntax. Any changes to the translations' meanings must be accompanied by equivalent changes to the English article.\n\nThere are some cases where the content is allowed to differ:\n\n- Articles originally written in a language other than English (in this case, English should act as the translation)\n- Explanations of English words that are common terms in the osu! community\n- External links\n- Tags\n- Subcommunity-specific explanations\n\n## Front matter\n\nFront matter must be placed at the very top of the file. It is written in [YAML](https://en.wikipedia.org/wiki/YAML#Example \"YAML Wikipedia article\") and describes additional information about the article. This must be surrounded by three hyphens (`---`) on the lines above and below it, and an empty line must follow it before the title heading.\n\n### Articles that need help\n\n*Note: Avoid translating English articles with this tag. In addition to this, this tag should be added when the translation needs its own clean up.*\n\nThe `needs_cleanup` tag may be added to articles that need rewriting or formatting help. It is also acceptable to open an issue on GitHub for this purpose. This tag must be written as shown below:\n\n```yaml\nneeds_cleanup: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be done to remove the tag.\n\n### Outdated articles\n\n*Note: Avoid translating English articles with this tag. If the English article has this tag, the translation must also have this tag.*\n\nTranslated articles that are outdated must use the `outdated` tag when the English variant is updated. English articles may also become outdated when the content they contain is misleading or no longer relevant. This tag must be written as shown below:\n\n```yaml\noutdated: true\n```\n\nWhen adding this tag to an article, [comments](#comments) should also be added to explain what needs to be updated to remove the tag.\n\n### Tagging articles\n\nTags help the website's search engine query articles better. Tags should be written in the same language as the article and include the original list of tags. Tags should use lowercase letters where applicable.\n\nFor example, an article called \"Beatmap discussion\" may include the following tags:\n\n```yaml\ntags:\n - beatmap discussions\n - modding V2\n - MV2\n```\n\n### Translations without reviews\n\n*Note: Wiki maintainers will determine and apply this mark prior to merging.*\n\nSometimes, translations are added to the wiki without review from other native speakers of the language. In this case, the `no_native_review` mark is added to let future translators know that it may need to be checked again. This tag must be written as shown below:\n\n```yaml\nno_native_review: true\n```\n\n## Article naming\n\n*See also: [Folder names](#folder-names) and [Titles](#titles)*\n\nArticle titles should be singular and use sentence case. See [Wikipedia's naming conventions article](https://en.wikipedia.org/wiki/Wikipedia:Naming_conventions_(plurals) \"Wikipedia\") for more details.\n\nArticle titles should match the folder name it is in (spaces may replace underscores (`_`) where appropriate). If the folder name changes, the article title should be changed to match it and vice versa.\n\n---\n\nContest and tournament articles are an exception. The folder name must use abbreviations, acronyms, or initialisms. The article's title must be the full name of the contest or tournament.\n\n## Folder and file structure\n\n### Folder names\n\n*See also: [Article naming](#article-naming)*\n\nFolder names must be in English and use sentence case.\n\nFolder names must only use these characters:\n\n- uppercase and lowercase letters\n- numbers\n- underscores (`_`)\n- hyphens (`-`)\n- exclamation marks (`!`)\n\n### Article file names\n\nThe file name of an article can be found in the `File Name` column of the [locales section](#locales). The location of a translated article must be placed in the same folder as the English article.\n\n### Index articles\n\nAn index article must be created if the folder is intended to only hold other articles. Index articles must contain a list of articles that are inside its own folder. They may also contain other information, such as a lead paragraph or descriptions of the linked articles.\n\n### Disambiguation articles\n\n[Disambiguation](/wiki/Disambiguation) articles must be placed in the `/wiki/Disambiguation` folder. The main page must be updated to include the disambiguation article. Refer to [Disambiguation/Mod](/wiki/Disambiguation/Mod) as an example.\n\nRedirects must be updated to have the ambiguous keyword(s) redirect to the disambiguation article.\n\nArticles linked from a disambiguation article must have a [For other uses](#for-other-uses) hatnote.\n\n## HTML\n\nHTML must not be used, with exception for [comments](#comments). The structure of the article must be redone if HTML is used.\n\n### Comments\n\nHTML comments should be used for marking to-dos, but may also be used to annotate text. They should be on their own line, but can be placed inline in a paragraph. If placed inline, the start of the comment must not have a space.\n\nBad example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\nGood example:\n\n```markdown\nHTML comments should be used for marking to-dos or annotate text.\n```\n\n## Editing\n\n### End of line sequence\n\n*Caution: Uploading Markdown files using `CRLF` (carriage return and line feed) via GitHub will result in those files using `CRLF`. To prevent this, set the line ending to `LF` (line feed) before uploading.*\n\nMarkdown files must be checked in using the `LF` end of line sequence.\n\n### Escaping\n\nMarkdown syntax should be escaped as needed. However, article titles are parsed as plain text and so must not be escaped.\n\n### Paragraphs\n\nEach paragraph must be followed by one empty line.\n\n### Line breaks\n\nLine breaks must use a backslash (`\\`).\n\nLine breaks must be used sparingly.\n\n## Hatnote\n\n*Not to be confused with [Notice](#notice).*\n\nHatnotes are short notes placed at the top of an article or section to help readers navigate to related articles or inform them about related topics.\n\nHatnotes must be italicised and be placed immediately after the heading. If multiple hatnotes are used, they must be on the same paragraph separated with a line break.\n\n### Main page\n\n*Main page* hatnotes direct the reader to the main article of a topic. When this hatnote is used, it implies that the section it is on is a summary of what the linked page is about. This hatnote should have only one link. These must be formatted as follows:\n\n```markdown\n*Main page: {article}*\n\n*Main pages: {article} and {article}*\n```\n\n### See also\n\n*See also* hatnotes suggest to readers other points of interest from a given article or section. These must be formatted as follows:\n\n```markdown\n*See also: {article}*\n\n*See also: {article} and {article}*\n```\n\n### For see\n\n*For see* hatnotes are similar to *see also* hatnotes, but are generally more descriptive and direct. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*For {description}, see: {article}`*\n\n*For {description}, see: {article} and {article}`*\n```\n\n### Not to be confused with\n\n*Not to be confused with* hatnotes help distinguish ambiguous or misunderstood article titles or sections. This hatnote may use more than one link if necessary. These must be formatted as follows:\n\n```markdown\n*Not to be confused with {article}.*\n\n*Not to be confused with {article} or {article}.*\n```\n\n### For other uses\n\n*For other uses* hatnotes are similar to *not to be confused with* hatnotes, but links directly to the [disambiguation article](#disambiguation-articles). This hatnote must only link to the disambiguation article. These must be formatted as follows:\n\n```markdown\n*For other uses, see {disambiguation article}.*\n```\n\n## Notice\n\n*Not to be confused with [Hatnote](#hatnote).*\n\nA notice should be placed where appropriate in a section, but must start off the paragraph and use italics. Notices may contain bolding where appropriate, but should be kept to a minimum. Notices must be written as complete sentences. Thus, unlike most [hatnotes](#hatnotes), must use a full stop (`.`) or an exclamation mark (`!`) if appropriate. Anything within the same paragraph of a notice must also be italicised. These must be formatted as follows:\n\n```markdown\n*Note: {note}.*\n\n*Notice: {notice}.*\n\n*Caution: {caution}.*\n\n*Warning: {warning}.*\n```\n\n- `Note` should be used for factual or trivial details.\n- `Notice` should be used for reminders or to draw attention to something that the reader should be made aware of.\n- `Caution` should be used to warn the reader to avoid unintended consequences.\n- `Warning` should be used to warn the reader that action may be taken against them.\n\n## Emphasising\n\n### Bold\n\nBold must use double asterisks (`**`).\n\nLead paragraphs may bold the first occurrence of the article's title.\n\n### Italics\n\nItalics must use single asterisks (`*`).\n\nNames of work or video games should be italicised. osu!—the game—is exempt from this.\n\nThe first occurrence of an abbreviation, acronym, or initialism may be italicised.\n\nItalics may also be used to provide emphasis or help with readability.\n\n## Headings\n\nAll headings must use sentence case.\n\nHeadings must use the [ATX (hash) style](https://github.github.com/gfm/#atx-headings \"GitHub\") and must have an empty line before and after the heading. The title heading is an exception when it is on the first line. If this is the case, there only needs to be an empty line after the title heading.\n\nHeadings must not exceed a heading level of 5 and must not be used to style or format text.\n\n### Titles\n\n*See also: [Article naming](#article-naming)*\n\n*Caution: Titles are parsed as plain text; they must not be escaped.*\n\nThe first heading in all articles must be a level 1 heading, being the article's title. All headings afterwards must be [section headings](#sections). Titles must not contain formatting, links, or images.\n\nThe title heading must be on the first line, unless [front matter](#front-matter) is being used. If that is the case, the title heading must go after it and have an empty line before the title heading.\n\n### Sections\n\nSection headings must use levels 2 to 5. The section heading proceeding the [title heading](#titles) must be a level 2 heading. Unlike titles, section headings may have small image icons.\n\nSection headings must not skip a heading level (i.e. do not go from a level 2 heading to a level 4 heading) and must not contain formatting or links.\n\n*Notice: On the website, heading levels 4 and 5 will not appear in the table of contents. They cannot be linked to directly either.*\n\n## Lists\n\nLists should not go over 4 levels of indentation and should not have an empty line in between each item.\n\nFor nested lists, bullets or numbers must align with the item content of their parent lists.\n\nThe following example was done incorrectly (take note of the spacing before the bullet):\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\nThe following example was done correctly:\n\n```markdown\n1. Fly a kite\n - Don't fly a kite if it's raining\n```\n\n### Bulleted\n\nBulleted lists must use a hyphen (`-`). These must then be followed by one space. (Example shown below.)\n\n```markdown\n- osu!\n - Hit circle\n - Combo number\n - Approach circle\n - Slider\n - Hit circles\n - Slider body\n - Slider ticks\n - Spinner\n- osu!taiko\n```\n\n### Numbered\n\nThe numbers in a numbered list must be incremented to represent their step.\n\n```markdown\n1. Download the osu! installer.\n2. Run the installer.\n 1. To change the installation location, click the text underneath the progression bar.\n 2. The installer will prompt for a new location, choose the installation folder.\n3. osu! will start up once installation is complete.\n4. Sign in.\n```\n\n### Mixed\n\nCombining both bulleted and numbered lists should be done sparingly.\n\n```markdown\n1. Download a skin from the forums.\n2. Load the skin file into osu!.\n - If the file is a `.zip`, unzip it and move the contents into the `Skins/` folder (found in your osu! installation folder).\n - If the file is a `.osk`, open it on your desktop or drag-and-drop it into the game client.\n3. Open osu!, if it is not opened, and select the skin in the options.\n - This may have been completed if you opened the `.osk` file or drag-and-dropped it into the game client.\n```\n\n## Code\n\nThe markup for code is a grave mark (`` ` ``). To put grave marks in code, use double grave marks instead. If the grave mark is at the start or end, pad it with one space. (Example shown below.)\n\n```markdown\n`` ` ``\n`` `Space` ``\n```\n\n### Keyboard keys\n\n*Notice: When denoting the letter itself, and not the keyboard key, use quotation marks instead.*\n\nWhen representing keyboard keys, use capital letters for single characters and title case for modifiers. Use the plus symbol (`+`) (without code) to represent key combinations. (Example shown below.)\n\n```markdown\npippi is spelt with a lowercase \"p\" like peppy.\n\nPress `Ctrl` + `O` to open the open dialog.\n```\n\nWhen representing a space or the spacebar, use `` `Space` ``.\n\n### Button and menu text\n\nWhen copying the text from a menu or button, the letter casing should be copied as it appears. (Example shown below.)\n\n```markdown\nThe `osu!direct` button is visible in the main menu on the right side, if you have an active osu!supporter tag.\n```\n\n### Folder and directory names\n\nWhen copying the name of a folder or directory, the letter casing should be copied as it appears, but prefer lowercased paths when possible. Directory paths must not be absolute (i.e. do not start the directory name from the drive letter or from the root folder). (Example shown below.)\n\n```markdown\nosu! is installed in the `AppData/Local` folder by default, unless specified otherwise during installation.\n```\n\n### Keywords and commands\n\nWhen copying a keyword or command, the letter casing should be copied as it appears or how someone normally would type it. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nAs of now, the `Name` and `Author` commands in the skin configuration file (`skin.ini`) do nothing.\n```\n\n### File names\n\nWhen copying the name of a file, the letter casing should be copied as it appears. If applicable, prefer lowercase letters. (Example shown below.)\n\n```markdown\nTo play osu!, double click the `osu!.exe` icon.\n```\n\n### File extensions\n\n*Notice: File formats (not to be confused with file extensions) must be written in capital letters without the prefixed fullstop (`.`).*\n\nFile extensions must be prefixed with a fullstop (`.`) and be followed by the file extension in lowercase letters. (Example shown below.)\n\n```markdown\nThe JPG (or JPEG) file format has the `.jpg` (or `.jpeg`) extension.\n```\n\n### Chat channels\n\nWhen copying the name of a chat channel, start it with a hash (`#`), followed by the channel name in lowercase letters. (Example shown below.)\n\n```markdown\n`#lobby` is where you can advertise your multi room.\n```\n\n## Preformatted text (code blocks)\n\n*Notice: Syntax highlighting for preformatted text is not implemented on the website yet.*\n\nPreformatted text (also known as code blocks) must be fenced using three grave marks. They should set the language identifier for syntax highlighting.\n\n## Links\n\nThere are two types of links: inline and reference. Inline has two styles.\n\nThe following is an example of both inline styles:\n\n```markdown\n[Game Modifiers](/wiki/Game_Modifiers)\n\n\n```\n\nThe following is an example of the reference style:\n\n```markdown\n[Game Modifiers][game mods link]\n\n[game mods link]: /wiki/Game_Modifiers\n```\n\n---\n\nLinks must use the inline style if they are only referenced once. The inline angle brackets style should be avoided. References to reference links must be placed at the bottom of the article.\n\n### Internal links\n\n*Note: Internal links refer to links that stay inside the `https://osu.ppy.sh/` domain.*\n\n#### Wiki links\n\nAll links that point to an wiki article should start with `/wiki/` followed by the path to get to the article you are targeting. Relative links may also be used. Some examples include the following:\n\n```markdown\n[FAQ](/wiki/FAQ)\n[pippi](/wiki/Mascots#-pippi)\n[Beatmaps](../)\n[Pattern](./Pattern)\n```\n\nWiki links must not use redirects and must not have a trailing forward slash (`/`).\n\nBad examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/ASC)\n[Developers](/wiki/Developers/)\n[Developers](/wiki/Developers/#game-client-developers)\n```\n\nGood examples include the following:\n\n```markdown\n[Article styling criteria](/wiki/Article_styling_criteria)\n[Developers](/wiki/Developers)\n[Developers](/wiki/Developers#game-client-developers)\n```\n\n##### Sub-article links\n\nWiki links that point to a sub-article should include the parent article's folder name in its link text. See the following example:\n\n```markdown\n*See also: [Beatmap Editor/Design](/wiki/Beatmap_Editor/Design)*\n```\n\n##### Section links\n\n*Notice: On the website, heading levels 4 and 5 are not given the id attribute. This means that they can not be linked to directly.*\n\nWiki links that point to a section of an article may use the section sign symbol (`§`). See the following example:\n\n```markdown\n*For timing rules, see: [Ranking Criteria § Timing](/wiki/Ranking_Criteria#timing)*\n```\n\n#### Other osu! links\n\nThe URL from the address bar of your web browser should be copied as it is when linking to other osu! web pages. The `https://osu.ppy.sh` part of the URL must be kept.\n\n##### User profiles\n\nAll usernames must be linked on first occurrence. Other occurrences are optional, but must be consistent throughout the entire article for all usernames. If it is difficult to determine the user's id, it may be skipped over.\n\nWhen linking to a user profile, the user's id number must be used. Use the new website (`https://osu.ppy.sh/users/{username})`) to get the user's id.\n\nThe link text of the user link should be the user's current name.\n\n##### Difficulties\n\nWhenever linking to a single difficulty, use this format as the link text:\n\n```\n{artist} - {title} ({creator}) [{difficuty_name}]\n```\n\nThe link must actually link to that difficulty. Beatmap difficulty URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}#{mode}/{BeatmapID}\n```\n\nThe difficulty name may be left outside of the link text, but doing so must be consistent throughout the entire article.\n\n##### Beatmaps\n\nWhenever linking to a beatmap, use this format as the link text:\n\n```\n{artist} - {title} ({creator})\n```\n\nAll beatmap URLs must be formatted as follows:\n\n```\nhttps://osu.ppy.sh/beatmapsets/{BeatmapSetID}\n```\n\n### External links\n\n*Notice: External links refers to links that go outside the `https://osu.ppy.sh/` domain.*\n\nThe `https` protocol must be used, unless the site does not support it. External links must be a clean and direct link to a reputable source. The link text should be the title of the page it is linking to. The URL from the address bar of your web browser should be copied as it is when linking to other external pages.\n\nThere are no visual differences between external and osu! web links. Due to this, the website name should be included in the title text. See the following example:\n\n```markdown\n*For more information about music theory, see: [Music theory](https://en.wikipedia.org/wiki/Music_theory \"Wikipedia\")*\n```\n\n## Images\n\nThere are two types of image links: inline and reference. Examples:\n\n**Inline style:**\n\n```markdown\n![](/wiki/shared/flag/AU.gif)\n```\n\n**Reference style:**\n\n```markdown\n![][flag_AU]\n\n[flag_AU]: /wiki/shared/flag/AU.gif\n```\n\nImages should use the inline linking style. References to reference links must be placed at the bottom of the article.\n\nImages must be placed in a folder named `img`, located in the article's folder. Images that are used in multiple articles should be stored in the `/wiki/shared/` folder.\n\n### Image caching\n\nImages on the website are cached for up to 60 days. The cached image is matched with the image link's URL.\n\nWhen updating an image, either change the image's name or append a query string to the URL. In both cases, all translations linking to the updated image should also be updated.\n\n### Formats and quality\n\nImages should use the JPG format at quality 8 (80 or 80%, depending on the program). If the image contains transparency or has text that must be readable, use the PNG format instead. If the image contains an animation, the GIF format can be used; however, this should be used sparingly as these may take longer to load or can be bigger then the [max file size](#file-size).\n\n### File size\n\nImages must be under 1 megabyte, otherwise they will fail to load. Downscaling and using JPG at 80% is almost always under the size limit.\n\nAll images should be optimised as much as possible. Use [jpeg-archive](https://github.com/danielgtaylor/jpeg-archive \"GitHub\") to compress JPEG images. For consistency, use the following command for jpeg-archive:\n\n```sh\njpeg-recompress -am smallfry \n```\n\nWhere `` is the file name to be compressed and `` is the compressed file name.\n\n### File names\n\n*Notice: File extensions must use lowercase letters, otherwise they will fail to load!*\n\nUse hyphens (`-`) when spacing words. When naming an image, the file name should be meaningful or descriptive but short.\n\n### Formatting and positioning\n\n*Note: It is currently not possible to float an image or have text wrap around it.*\n\nImages on the website will be centred when it is on a single line, by themself. Otherwise, they will be positioned inline with the paragraph. The following example will place the image in the center:\n\n```markdown\nInstalling osu! is easy. First, download the installer from the download page.\n\n![](img/download-page.jpg)\n\nThen locate the installer and run it.\n```\n\n### Alt text\n\nImages should have alt text unless it is for decorative purposes.\n\n### Captions\n\nImages are given captions on the website if they fulfill these conditions:\n\n1. The image is by itself.\n2. The image is not inside a heading.\n3. The image has title text.\n\nCaptions are assumed via the title text, which must be in plain text. Images with captions are also centred with the image on the website.\n\n### Max image width\n\nThe website's max image width is the width of the article body. Images should be no wider than 800 pixels.\n\n### Annotating images\n\nWhen annotating images, use *Torus Regular*. For Chinese, Korean, Japanese characters, use *Microsoft YaHei*.\n\nAnnotating images should be avoided, as it is difficult for translators (and other editors) to edit them.\n\n#### Translating annotated images\n\nWhen translating annotated images, the localised image version must be placed in the same directory as the original version (i.e. the English version). The filename of a localised image version must start with the original version's name, followed by a hyphen, followed by the locale name (in capital letters). See the following examples:\n\n- `hardrock-mod-vs-easy-mod.jpg` for English\n- `hardrock-mod-vs-easy-mod-DE.jpg` for German\n- `hardrock-mod-vs-easy-mod-ZH-TW.jpg` for Traditional Chinese\n\n### Screenshots of gameplay\n\nAll screenshots of gameplay must be done in the stable build, unless it is for a specific feature that is unavailable in the stable build. You should use the in-game screenshot feature (`F12`).\n\n#### Game client settings\n\n*Note: If you do not want to change your current settings for the wiki, you can move your `osu!..cfg` out of the osu! folder and move it back later.*\n\nYou must set these settings before taking a screenshot of the game client (settings not stated below are assumed to be at their defaults):\n\n- Select language: `English`\n- Prefer metadata in original language: `Enabled`\n- Resolution: `1280x720`\n- Fullscreen mode: `Disabled`\n- Parallax: `Disabled`\n- Menu tips: `Disabled`\n- Seasonal backgrounds: `Never`\n- Always show key overlay: `Enabled`\n- Current skin: `Default` (first option)\n\n*Notice to translators: If you are translating an article containing screenshots of the game, you may set the game client's language to the language you are translating in.*\n\n### Image links\n\nImages must not be part of a link text.\n\nFlag icons next to user links must be separate from the link text. See the following example:\n\n```markdown\n![][flag_AU] [peppy](https://osu.ppy.sh/users/2)\n```\n\n### Flag icons\n\n*For a list of flag icons, see: [issue \\#328](https://github.com/ppy/osu-wiki/issues/328 \"GitHub\")*\n\nThe flag icons use the two letter code (in all capital letters) and end with `.gif`. When adding a flag inline, use this format:\n\n```markdown\n![](/wiki/shared/flag/xx.gif)\n```\n\nWhere `xx` is the [ISO 3166-2](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2 \"Wikipedia\") two-lettered country code for the flag.\n\nThe full country name should be added in the title text. The country code in the alternate text is optional, but must be applied to all flag icons in the article.\n\n## Tables\n\nTables on the website only support headings along the first row.\n\nTables must not be beautified (do not pad cells with extra spaces to make their widths uniform). They must have a vertical bar (`|`) on the left and right sides and the text of each cell must be padded with one space on both sides. Empty cells must use a vertical bar (`|`) followed by two spaces then another vertical bar (`|`).\n\nThe delimiter row (the next line after the table heading) must use only three characters per column (and be padded with a space on both sides), which must look like one of the following:\n\n- `:--` (for left align)\n- `:-:` (for centre align)\n- `--:` (for right align)\n\n---\n\nThe following is an example of what a table should look like:\n\n```markdown\n| Team \"Picturesque\" Red | Score | Team \"Statuesque\" Blue | Average Beatmap Stars |\n| :-- | :-: | --: | :-- |\n| **peppy** | 5 - 2 | pippi | 9.3 stars |\n| Aiko | 1 - 6 | **Alisa** | 4.2 stars |\n| Ryūta | 3 - 4 | **Yuzu** | 5.1 stars |\n| **Taikonator** | 7 - 0 | Tama | 13.37 stars |\n| Maria | No Contest | Mocha | |\n```\n\n## Blockquotes\n\nThe blockquote is limited to quoting text from someone. It must not be used to format text otherwise.\n\n## Thematic breaks\n\nThe thematic break (also known as the horizontal rule or line) should be used sparingly. A few uses of the thematic break may include (but is not limited to):\n\n- separating images from text\n- separating multiple images that follow one another\n- shifting the topic within a section\n\nThese must have an empty line before and after the markup. Thematic breaks must use only three hyphens, as depicted below:\n\n```markdown\n---\n```\n" }; } } diff --git a/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs new file mode 100644 index 0000000000..b4f1997bb0 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneWikiSidebar.cs @@ -0,0 +1,65 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Parsers; +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Game.Graphics.Containers.Markdown; +using osu.Game.Overlays; +using osu.Game.Overlays.Wiki; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneWikiSidebar : OsuTestScene + { + [Cached] + private readonly OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Orange); + + [Cached] + private readonly OverlayScrollContainer scrollContainer = new OverlayScrollContainer(); + + private WikiSidebar sidebar; + + [SetUp] + public void SetUp() => Schedule(() => Child = sidebar = new WikiSidebar()); + + [Test] + public void TestNoContent() + { + AddStep("No Content", () => { }); + } + + [Test] + public void TestOnlyMainTitle() + { + AddStep("Add TOC", () => + { + for (var i = 0; i < 10; i++) + addTitle($"This is a very long title {i + 1}"); + }); + } + + [Test] + public void TestWithSubtitle() + { + AddStep("Add TOC", () => + { + for (var i = 0; i < 10; i++) + addTitle($"This is a very long title {i + 1}", i % 4 != 0); + }); + } + + private void addTitle(string text, bool subtitle = false) + { + var headingBlock = new HeadingBlock(new HeadingBlockParser()) + { + Inline = new ContainerInline().AppendChild(new LiteralInline(text)), + Level = subtitle ? 3 : 2, + }; + var heading = new OsuMarkdownHeading(headingBlock); + sidebar.AddEntry(headingBlock, heading); + } + } +} diff --git a/osu.Game/Overlays/OnlineOverlay.cs b/osu.Game/Overlays/OnlineOverlay.cs index de33e4a1bc..a610511398 100644 --- a/osu.Game/Overlays/OnlineOverlay.cs +++ b/osu.Game/Overlays/OnlineOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics.UserInterface; @@ -13,7 +14,9 @@ namespace osu.Game.Overlays { protected override Container Content => content; + [Cached] protected readonly OverlayScrollContainer ScrollFlow; + protected readonly LoadingLayer Loading; private readonly Container content; diff --git a/osu.Game/Overlays/Wiki/WikiArticlePage.cs b/osu.Game/Overlays/Wiki/WikiArticlePage.cs new file mode 100644 index 0000000000..0061bff8ea --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiArticlePage.cs @@ -0,0 +1,80 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using Markdig.Syntax; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Overlays.Wiki.Markdown; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiArticlePage : CompositeDrawable + { + public Container SidebarContainer { get; } + + public WikiArticlePage(string currentPath, string markdown) + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + + WikiSidebar sidebar; + + InternalChild = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] + { + SidebarContainer = new Container + { + AutoSizeAxes = Axes.X, + Child = sidebar = new WikiSidebar(), + }, + new ArticleMarkdownContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + CurrentPath = currentPath, + Text = markdown, + DocumentMargin = new MarginPadding(0), + DocumentPadding = new MarginPadding + { + Vertical = 20, + Left = 30, + Right = 50, + }, + OnAddHeading = sidebar.AddEntry, + } + }, + }, + }; + } + + private class ArticleMarkdownContainer : WikiMarkdownContainer + { + public Action OnAddHeading; + + protected override MarkdownHeading CreateHeading(HeadingBlock headingBlock) + { + var heading = base.CreateHeading(headingBlock); + + OnAddHeading(headingBlock, heading); + + return heading; + } + } + } +} diff --git a/osu.Game/Overlays/Wiki/WikiSidebar.cs b/osu.Game/Overlays/Wiki/WikiSidebar.cs new file mode 100644 index 0000000000..ee4e195f3f --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiSidebar.cs @@ -0,0 +1,66 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using Markdig.Syntax; +using Markdig.Syntax.Inlines; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiSidebar : OverlaySidebar + { + private WikiTableOfContents tableOfContents; + + protected override Drawable CreateContent() => new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "CONTENTS", + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Margin = new MarginPadding { Bottom = 5 }, + }, + tableOfContents = new WikiTableOfContents(), + }, + }; + + public void AddEntry(HeadingBlock headingBlock, MarkdownHeading heading) + { + switch (headingBlock.Level) + { + case 2: + case 3: + tableOfContents.AddEntry(getTitle(headingBlock.Inline), heading, headingBlock.Level == 3); + break; + } + } + + private string getTitle(ContainerInline containerInline) + { + foreach (var inline in containerInline) + { + switch (inline) + { + case LiteralInline literalInline: + return literalInline.Content.ToString(); + + case LinkInline linkInline: + if (!linkInline.IsImage) + return getTitle(linkInline); + + break; + } + } + + return string.Empty; + } + } +} diff --git a/osu.Game/Overlays/Wiki/WikiTableOfContents.cs b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs new file mode 100644 index 0000000000..c0615dce1f --- /dev/null +++ b/osu.Game/Overlays/Wiki/WikiTableOfContents.cs @@ -0,0 +1,91 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Collections.Generic; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Containers.Markdown; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; + +namespace osu.Game.Overlays.Wiki +{ + public class WikiTableOfContents : CompositeDrawable + { + private readonly FillFlowContainer content; + + private TableOfContentsEntry lastMainTitle; + + private TableOfContentsEntry lastSubTitle; + + public WikiTableOfContents() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + InternalChild = content = new FillFlowContainer + { + Direction = FillDirection.Vertical, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + }; + } + + public void AddEntry(string title, MarkdownHeading target, bool subtitle = false) + { + var entry = new TableOfContentsEntry(title, target, subtitle); + + if (subtitle) + { + lastMainTitle.Margin = new MarginPadding(0); + + if (lastSubTitle != null) + lastSubTitle.Margin = new MarginPadding(0); + + content.Add(lastSubTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 10 })); + + return; + } + + lastSubTitle = null; + + content.Add(lastMainTitle = entry.With(d => d.Margin = new MarginPadding { Bottom = 5 })); + } + + private class TableOfContentsEntry : OsuHoverContainer + { + private readonly MarkdownHeading target; + + private readonly OsuTextFlowContainer textFlow; + + public TableOfContentsEntry(string text, MarkdownHeading target, bool subtitle = false) + { + this.target = target; + + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Child = textFlow = new OsuTextFlowContainer(t => + { + t.Font = OsuFont.GetFont(size: subtitle ? 12 : 15); + }).With(f => + { + f.AddText(text); + f.RelativeSizeAxes = Axes.X; + f.AutoSizeAxes = Axes.Y; + f.Margin = new MarginPadding { Bottom = 2 }; + }); + Padding = new MarginPadding { Left = subtitle ? 10 : 0 }; + } + + protected override IEnumerable EffectTargets => new Drawable[] { textFlow }; + + [BackgroundDependencyLoader] + private void load(OverlayColourProvider colourProvider, OverlayScrollContainer scrollContainer) + { + IdleColour = colourProvider.Light2; + HoverColour = colourProvider.Light1; + Action = () => scrollContainer.ScrollTo(target); + } + } + } +} diff --git a/osu.Game/Overlays/WikiOverlay.cs b/osu.Game/Overlays/WikiOverlay.cs index c5ba0eed66..bde73b6180 100644 --- a/osu.Game/Overlays/WikiOverlay.cs +++ b/osu.Game/Overlays/WikiOverlay.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Linq; using System.Threading; using osu.Framework.Allocation; @@ -10,7 +11,6 @@ using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Wiki; -using osu.Game.Overlays.Wiki.Markdown; namespace osu.Game.Overlays { @@ -31,6 +31,8 @@ namespace osu.Game.Overlays private bool displayUpdateRequired = true; + private WikiArticlePage articlePage; + public WikiOverlay() : base(OverlayColourScheme.Orange, false) { @@ -82,6 +84,17 @@ namespace osu.Game.Overlays }, (cancellationToken = new CancellationTokenSource()).Token); } + protected override void UpdateAfterChildren() + { + base.UpdateAfterChildren(); + + if (articlePage != null) + { + articlePage.SidebarContainer.Height = DrawHeight; + articlePage.SidebarContainer.Y = Math.Clamp(ScrollFlow.Current - Header.DrawHeight, 0, Math.Max(ScrollFlow.ScrollContent.DrawHeight - DrawHeight - Header.DrawHeight, 0)); + } + } + private void onPathChanged(ValueChangedEvent e) { cancellationToken?.Cancel(); @@ -115,39 +128,14 @@ namespace osu.Game.Overlays } else { - LoadDisplay(new WikiMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = $@"{api.WebsiteRootUrl}/wiki/{path.Value}/", - Text = response.Markdown, - DocumentMargin = new MarginPadding(0), - DocumentPadding = new MarginPadding - { - Vertical = 20, - Left = 30, - Right = 50, - }, - }); + LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/{path.Value}/", response.Markdown)); } } private void onFail() { - LoadDisplay(new WikiMarkdownContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - CurrentPath = $@"{api.WebsiteRootUrl}/wiki/", - Text = $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).", - DocumentMargin = new MarginPadding(0), - DocumentPadding = new MarginPadding - { - Vertical = 20, - Left = 30, - Right = 50, - }, - }); + LoadDisplay(articlePage = new WikiArticlePage($@"{api.WebsiteRootUrl}/wiki/", + $"Something went wrong when trying to fetch page \"{path.Value}\".\n\n[Return to the main page](Main_Page).")); } private void showParentPage() diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs index 0412085d1d..89f61785e8 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/BarHitErrorMeter.cs @@ -217,6 +217,9 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters if (!judgement.IsHit || judgement.HitObject.HitWindows?.WindowFor(HitResult.Miss) == 0) return; + if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) + return; + if (judgementsContainer.Count > max_concurrent_judgements) { const double quick_fade_time = 100; diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs index 86c0de8855..dda2a6da95 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/ColourHitErrorMeter.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Rulesets.Judgements; +using osu.Game.Rulesets.Scoring; using osuTK; using osuTK.Graphics; @@ -24,7 +25,13 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters InternalChild = judgementsFlow = new JudgementFlow(); } - protected override void OnNewJudgement(JudgementResult judgement) => judgementsFlow.Push(GetColourForHitResult(judgement.Type)); + protected override void OnNewJudgement(JudgementResult judgement) + { + if (!judgement.Type.IsScorable() || judgement.Type.IsBonus()) + return; + + judgementsFlow.Push(GetColourForHitResult(judgement.Type)); + } private class JudgementFlow : FillFlowContainer { diff --git a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs index 17a6e772fb..9844b9f10d 100644 --- a/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs +++ b/osu.Game/Screens/Play/HUD/HitErrorMeters/HitErrorMeter.cs @@ -41,6 +41,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters { switch (result) { + case HitResult.SmallTickMiss: + case HitResult.LargeTickMiss: case HitResult.Miss: return colours.Red; @@ -53,6 +55,8 @@ namespace osu.Game.Screens.Play.HUD.HitErrorMeters case HitResult.Good: return colours.GreenLight; + case HitResult.SmallTickHit: + case HitResult.LargeTickHit: case HitResult.Great: return colours.Blue; diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 94e67107c9..f9036780aa 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -32,6 +32,7 @@ using osu.Game.Scoring.Legacy; using osu.Game.Screens.Ranking; using osu.Game.Skinning; using osu.Game.Users; +using osuTK.Graphics; namespace osu.Game.Screens.Play { @@ -856,6 +857,7 @@ namespace osu.Game.Screens.Play { b.IgnoreUserSettings.Value = false; b.BlurAmount.Value = 0; + b.FadeColour(Color4.White, 250); // bind component bindables. b.IsBreakTime.BindTo(breakTracker.IsBreakTime); diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ce580e2b53..5f6b4ca2b0 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -184,8 +184,6 @@ namespace osu.Game.Screens.Play { if (epilepsyWarning != null) epilepsyWarning.DimmableBackground = b; - - b?.FadeColour(Color4.White, 800, Easing.OutQuint); }); Beatmap.Value.Track.AddAdjustment(AdjustableProperty.Volume, volumeAdjustment); @@ -334,6 +332,8 @@ namespace osu.Game.Screens.Play content.FadeInFromZero(400); content.ScaleTo(1, 650, Easing.OutQuint).Then().Schedule(prepareNewPlayer); + + ApplyToBackground(b => b?.FadeColour(Color4.White, 800, Easing.OutQuint)); } private void contentOut() diff --git a/osu.Game/Screens/Ranking/ResultsScreen.cs b/osu.Game/Screens/Ranking/ResultsScreen.cs index c1f5d92d17..9ec6b9c5b1 100644 --- a/osu.Game/Screens/Ranking/ResultsScreen.cs +++ b/osu.Game/Screens/Ranking/ResultsScreen.cs @@ -12,6 +12,8 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Bindings; using osu.Framework.Screens; +using osu.Game.Audio; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Input.Bindings; @@ -237,7 +239,7 @@ namespace osu.Game.Screens.Ranking ApplyToBackground(b => { b.BlurAmount.Value = BACKGROUND_BLUR; - b.FadeTo(0.5f, 250); + b.FadeColour(OsuColour.Gray(0.5f), 250); }); bottomPanel.FadeTo(1, 250); @@ -245,9 +247,11 @@ namespace osu.Game.Screens.Ranking public override bool OnExiting(IScreen next) { - ApplyToBackground(b => b.FadeTo(1, 250)); + if (base.OnExiting(next)) + return true; - return base.OnExiting(next); + this.FadeOut(100); + return false; } public override bool OnBackButton() diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index c80c58b87c..2ee8ed527f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 42d197d106..7832aaaf2d 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - +