├── .config └── dotnet-tools.json ├── .editorconfig ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE │ └── bug-report.yml ├── dependabot.yml └── workflows │ ├── ci.yml │ ├── experimental-release.yml │ └── release.yml ├── .gitignore ├── .vscode ├── launch.json └── tasks.json ├── LICENSE ├── README.md ├── osu.Game.Rulesets.Tau.Tests ├── Conversion │ ├── TauConversionTestScene.cs │ ├── TestSceneBeatConversion.cs │ ├── TestSceneHardBeatConversion.cs │ ├── TestSceneSliderConversion.cs │ └── TestSceneSpinnerConversion.cs ├── Mods │ ├── TestSceneAutopilot.cs │ ├── TestSceneAutoplay.cs │ ├── TestSceneCinema.cs │ ├── TestSceneDoubleTime.cs │ ├── TestSceneDual.cs │ ├── TestSceneEasy.cs │ ├── TestSceneFadeIn.cs │ ├── TestSceneFadeOut.cs │ ├── TestSceneFlashlight.cs │ ├── TestSceneHalfTime.cs │ ├── TestSceneHardRock.cs │ ├── TestSceneInverse.cs │ ├── TestSceneNightcore.cs │ ├── TestScenePerfect.cs │ ├── TestSceneRelax.cs │ ├── TestSceneRoundabout.cs │ ├── TestSceneShowoff.cs │ ├── TestSceneSuddenDeath.cs │ └── TestSceneTraceable.cs ├── NonVisual │ └── PolarSliderPathTests.cs ├── Objects │ ├── TestSceneAutoplayBeat.cs │ ├── TestSceneAutoplaySlider.cs │ ├── TestSceneBeat.cs │ ├── TestSceneHardBeat.cs │ ├── TestSceneSlider.cs │ ├── TestSceneSliderHardBeat.cs │ └── TestSceneStrictHardBeat.cs ├── TauModTestScene.cs ├── TauSkinnableTestScene.cs ├── TauTestScene.cs ├── TestSceneClassicKiai.cs ├── TestSceneDrawableJudgement.cs ├── TestSceneKiaiEffects.cs ├── TestSceneOsuGame.cs ├── TestSceneOsuPlayer.cs ├── TestScenePaddleDistribution.cs ├── TestSceneResumeOverlay.cs ├── TestSceneTauCursor.cs ├── TestSceneTauPlayfield.cs ├── TestSceneTurbulenceKiai.cs ├── TestSceneVisualizer.cs ├── VisualTestRunner.cs └── osu.Game.Rulesets.Tau.Tests.csproj ├── osu.Game.Rulesets.Tau.sln ├── osu.Game.Rulesets.Tau.sln.DotSettings └── osu.Game.Rulesets.Tau ├── Allocation └── MemoryPool.cs ├── Beatmaps ├── TauBeatmap.cs └── TauBeatmapConverter.cs ├── Configuration ├── KiaiType.cs └── TauRulesetConfigManager.cs ├── Difficulty ├── Evaluators │ ├── AimEvaluator.cs │ ├── ComplexityEvaluator.cs │ ├── RhythmEvaluator.cs │ └── SpeedEvaluator.cs ├── Preprocessing │ ├── TauAngledDifficultyHitObject.cs │ └── TauDifficultyHitObject.cs ├── Skills │ ├── Aim.cs │ ├── Complexity.cs │ ├── Speed.cs │ └── TauStrainSkill.cs ├── TauDifficultyAttributes.cs ├── TauDifficultyCalculator.cs ├── TauPerformanceAttribute.cs └── TauPerformanceCalculator.cs ├── Extensions.cs ├── Judgements ├── TauJudgement.cs ├── TauJudgementResult.cs └── TauTickJudgement.cs ├── Localisation ├── BeatmapStrings.cs ├── InputStrings.cs ├── KiaiTypeStrings.cs ├── ModStrings.cs ├── SettingStrings.cs ├── Translations │ ├── Beatmap.ar.resx │ ├── Beatmap.be.resx │ ├── Beatmap.bg.resx │ ├── Beatmap.ca.resx │ ├── Beatmap.cs.resx │ ├── Beatmap.da.resx │ ├── Beatmap.de.resx │ ├── Beatmap.el.resx │ ├── Beatmap.es.resx │ ├── Beatmap.fa.resx │ ├── Beatmap.fi.resx │ ├── Beatmap.fil.resx │ ├── Beatmap.fr.resx │ ├── Beatmap.he.resx │ ├── Beatmap.hr.resx │ ├── Beatmap.hu.resx │ ├── Beatmap.id.resx │ ├── Beatmap.it.resx │ ├── Beatmap.ja.resx │ ├── Beatmap.ko.resx │ ├── Beatmap.lt.resx │ ├── Beatmap.lv.resx │ ├── Beatmap.ms.resx │ ├── Beatmap.nl.resx │ ├── Beatmap.no.resx │ ├── Beatmap.pl.resx │ ├── Beatmap.pt.resx │ ├── Beatmap.pt_BR.resx │ ├── Beatmap.resx │ ├── Beatmap.ro.resx │ ├── Beatmap.ru.resx │ ├── Beatmap.si.resx │ ├── Beatmap.sk.resx │ ├── Beatmap.sl.resx │ ├── Beatmap.sr.resx │ ├── Beatmap.sv.resx │ ├── Beatmap.th.resx │ ├── Beatmap.tr.resx │ ├── Beatmap.uk.resx │ ├── Beatmap.vi.resx │ ├── Beatmap.zh-Hans.resx │ ├── Beatmap.zh-Hant.resx │ ├── Inputs.ar.resx │ ├── Inputs.be.resx │ ├── Inputs.bg.resx │ ├── Inputs.ca.resx │ ├── Inputs.cs.resx │ ├── Inputs.da.resx │ ├── Inputs.de.resx │ ├── Inputs.el.resx │ ├── Inputs.es.resx │ ├── Inputs.fa.resx │ ├── Inputs.fi.resx │ ├── Inputs.fil.resx │ ├── Inputs.fr.resx │ ├── Inputs.he.resx │ ├── Inputs.hr.resx │ ├── Inputs.hu.resx │ ├── Inputs.id.resx │ ├── Inputs.it.resx │ ├── Inputs.ja.resx │ ├── Inputs.ko.resx │ ├── Inputs.lt.resx │ ├── Inputs.lv.resx │ ├── Inputs.ms.resx │ ├── Inputs.nl.resx │ ├── Inputs.no.resx │ ├── Inputs.pl.resx │ ├── Inputs.pt.resx │ ├── Inputs.pt_BR.resx │ ├── Inputs.resx │ ├── Inputs.ro.resx │ ├── Inputs.ru.resx │ ├── Inputs.si.resx │ ├── Inputs.sk.resx │ ├── Inputs.sl.resx │ ├── Inputs.sr.resx │ ├── Inputs.sv.resx │ ├── Inputs.th.resx │ ├── Inputs.tr.resx │ ├── Inputs.uk.resx │ ├── Inputs.vi.resx │ ├── Inputs.zh-Hans.resx │ ├── Inputs.zh-Hant.resx │ ├── KiaiType.ar.resx │ ├── KiaiType.be.resx │ ├── KiaiType.bg.resx │ ├── KiaiType.ca.resx │ ├── KiaiType.cs.resx │ ├── KiaiType.da.resx │ ├── KiaiType.de.resx │ ├── KiaiType.el.resx │ ├── KiaiType.es.resx │ ├── KiaiType.fa.resx │ ├── KiaiType.fi.resx │ ├── KiaiType.fil.resx │ ├── KiaiType.fr.resx │ ├── KiaiType.he.resx │ ├── KiaiType.hr.resx │ ├── KiaiType.hu.resx │ ├── KiaiType.id.resx │ ├── KiaiType.it.resx │ ├── KiaiType.ja.resx │ ├── KiaiType.ko.resx │ ├── KiaiType.lt.resx │ ├── KiaiType.lv.resx │ ├── KiaiType.ms.resx │ ├── KiaiType.nl.resx │ ├── KiaiType.no.resx │ ├── KiaiType.pl.resx │ ├── KiaiType.pt.resx │ ├── KiaiType.pt_BR.resx │ ├── KiaiType.resx │ ├── KiaiType.ro.resx │ ├── KiaiType.ru.resx │ ├── KiaiType.si.resx │ ├── KiaiType.sk.resx │ ├── KiaiType.sl.resx │ ├── KiaiType.sr.resx │ ├── KiaiType.sv.resx │ ├── KiaiType.th.resx │ ├── KiaiType.tr.resx │ ├── KiaiType.uk.resx │ ├── KiaiType.vi.resx │ ├── KiaiType.zh-Hans.resx │ ├── KiaiType.zh-Hant.resx │ ├── Mods.ar.resx │ ├── Mods.be.resx │ ├── Mods.bg.resx │ ├── Mods.ca.resx │ ├── Mods.cs.resx │ ├── Mods.da.resx │ ├── Mods.de.resx │ ├── Mods.el.resx │ ├── Mods.es.resx │ ├── Mods.fa.resx │ ├── Mods.fi.resx │ ├── Mods.fil.resx │ ├── Mods.fr.resx │ ├── Mods.he.resx │ ├── Mods.hr.resx │ ├── Mods.hu.resx │ ├── Mods.id.resx │ ├── Mods.it.resx │ ├── Mods.ja.resx │ ├── Mods.ko.resx │ ├── Mods.lt.resx │ ├── Mods.lv.resx │ ├── Mods.ms.resx │ ├── Mods.nl.resx │ ├── Mods.no.resx │ ├── Mods.pl.resx │ ├── Mods.pt.resx │ ├── Mods.pt_BR.resx │ ├── Mods.resx │ ├── Mods.ro.resx │ ├── Mods.ru.resx │ ├── Mods.si.resx │ ├── Mods.sk.resx │ ├── Mods.sl.resx │ ├── Mods.sr.resx │ ├── Mods.sv.resx │ ├── Mods.th.resx │ ├── Mods.tr.resx │ ├── Mods.uk.resx │ ├── Mods.vi.resx │ ├── Mods.zh-Hans.resx │ ├── Mods.zh-Hant.resx │ ├── Settings.ar.resx │ ├── Settings.be.resx │ ├── Settings.bg.resx │ ├── Settings.ca.resx │ ├── Settings.cs.resx │ ├── Settings.da.resx │ ├── Settings.de.resx │ ├── Settings.el.resx │ ├── Settings.es.resx │ ├── Settings.fa.resx │ ├── Settings.fi.resx │ ├── Settings.fil.resx │ ├── Settings.fr.resx │ ├── Settings.he.resx │ ├── Settings.hr.resx │ ├── Settings.hu.resx │ ├── Settings.id.resx │ ├── Settings.it.resx │ ├── Settings.ja.resx │ ├── Settings.ko.resx │ ├── Settings.lt.resx │ ├── Settings.lv.resx │ ├── Settings.ms.resx │ ├── Settings.nl.resx │ ├── Settings.no.resx │ ├── Settings.pl.resx │ ├── Settings.pt.resx │ ├── Settings.pt_BR.resx │ ├── Settings.resx │ ├── Settings.ro.resx │ ├── Settings.ru.resx │ ├── Settings.si.resx │ ├── Settings.sk.resx │ ├── Settings.sl.resx │ ├── Settings.sr.resx │ ├── Settings.sv.resx │ ├── Settings.th.resx │ ├── Settings.tr.resx │ ├── Settings.uk.resx │ ├── Settings.vi.resx │ ├── Settings.zh-Hans.resx │ ├── Settings.zh-Hant.resx │ ├── UI.ar.resx │ ├── UI.be.resx │ ├── UI.bg.resx │ ├── UI.ca.resx │ ├── UI.cs.resx │ ├── UI.da.resx │ ├── UI.de.resx │ ├── UI.el.resx │ ├── UI.es.resx │ ├── UI.fa.resx │ ├── UI.fi.resx │ ├── UI.fil.resx │ ├── UI.fr.resx │ ├── UI.he.resx │ ├── UI.hr.resx │ ├── UI.hu.resx │ ├── UI.id.resx │ ├── UI.it.resx │ ├── UI.ja.resx │ ├── UI.ko.resx │ ├── UI.lt.resx │ ├── UI.lv.resx │ ├── UI.ms.resx │ ├── UI.nl.resx │ ├── UI.no.resx │ ├── UI.pl.resx │ ├── UI.pt.resx │ ├── UI.pt_BR.resx │ ├── UI.resx │ ├── UI.ro.resx │ ├── UI.ru.resx │ ├── UI.si.resx │ ├── UI.sk.resx │ ├── UI.sl.resx │ ├── UI.sr.resx │ ├── UI.sv.resx │ ├── UI.th.resx │ ├── UI.tr.resx │ ├── UI.uk.resx │ ├── UI.vi.resx │ ├── UI.zh-Hans.resx │ └── UI.zh-Hant.resx └── UiStrings.cs ├── Mods ├── TauModAutopilot.cs ├── TauModAutoplay.cs ├── TauModCinema.cs ├── TauModDaycore.cs ├── TauModDifficultyAdjust.cs ├── TauModDoubleTime.cs ├── TauModDual.cs ├── TauModEasy.cs ├── TauModFadeIn.cs ├── TauModFadeOut.cs ├── TauModFlashlight.cs ├── TauModHalfTime.cs ├── TauModHardRock.cs ├── TauModHidden.cs ├── TauModImpossibleSliders.cs ├── TauModInverse.cs ├── TauModLenience.cs ├── TauModLite.cs ├── TauModNightcore.cs ├── TauModNoFail.cs ├── TauModNoScope.cs ├── TauModPerfect.cs ├── TauModRelax.cs ├── TauModRoundabout.cs ├── TauModShowoffAutoplay.cs ├── TauModStrict.cs ├── TauModSuddenDeath.cs └── TauModTraceable.cs ├── Objects ├── AngledTauHitObject.cs ├── Beat.cs ├── Drawables │ ├── DrawableAngledTauHitObject.cs │ ├── DrawableBeat.cs │ ├── DrawableHardBeat.cs │ ├── DrawableSlider.Calculations.cs │ ├── DrawableSlider.Graphics.SliderPathDrawNode.cs │ ├── DrawableSlider.Graphics.cs │ ├── DrawableSlider.cs │ ├── DrawableSliderHardBeat.cs │ ├── DrawableSliderHead.cs │ ├── DrawableSliderRepeat.cs │ ├── DrawableSliderTick.cs │ ├── DrawableStrictHardBeat.cs │ ├── DrawableTauHitObject.cs │ ├── DrawableTauJudgement.cs │ ├── ICanApplyResult.cs │ └── Pieces │ │ ├── BeatPiece.cs │ │ ├── HardBeatPiece.cs │ │ ├── SkinnableLighting.cs │ │ └── StrictHardBeatPiece.cs ├── HardBeat.cs ├── IHasAngle.cs ├── IHasOffsetAngle.cs ├── PolarSliderPath.cs ├── Slider.cs ├── SliderHardBeat.cs ├── SliderHeadBeat.cs ├── SliderRepeat.cs ├── SliderTick.cs ├── StrictHardBeat.cs └── TauHitObject.cs ├── Replays ├── ShowoffAutoGenerator.cs ├── TauAutoGenerator.cs ├── TauAutoGeneratorBase.cs ├── TauFramedReplayInputHandler.cs └── TauReplayFrame.cs ├── Resources ├── Fonts │ ├── tauFont.fnt │ └── tauFont_0.png └── Shaders │ ├── sh_PlayfieldMask.fs │ ├── sh_Slider.fs │ ├── sh_SliderPositionAndColour.vs │ ├── sh_TriangularFlashlight.fs │ ├── sh_VisualizerFade.fs │ └── sh_VisualizerPositionAndColour.vs ├── Scoring ├── TauHitWindow.cs └── TauScoreProcessor.cs ├── Statistics └── PaddleDistributionGraph.cs ├── TauIcons.cs ├── TauInputManager.cs ├── TauRuleset.cs ├── UI ├── Cursor │ ├── AbsoluteCursor.cs │ ├── CursorPiece.cs │ ├── HandlePiece.cs │ └── Paddle.cs ├── Effects │ ├── ClassicKiaiEffect.cs │ ├── KiaiEffect.cs │ ├── KiaiEffectContainer.cs │ ├── PlayfieldVisualizer.cs │ └── TurbulenceKiaiEffect.cs ├── EffectsContainer.cs ├── PlayfieldPiece.cs ├── TauCachedProperties.cs ├── TauCursor.cs ├── TauDrawableRuleset.cs ├── TauPlayfield.cs ├── TauPlayfieldAdjustmentContainer.cs ├── TauReplayRecorder.cs ├── TauResumeOverlay.cs └── TauSettingsSubsection.cs └── osu.Game.Rulesets.Tau.csproj /.config/dotnet-tools.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": 1, 3 | "isRoot": true, 4 | "tools": { 5 | "jetbrains.resharper.globaltools": { 6 | "version": "2023.3.3", 7 | "commands": [ 8 | "jb" 9 | ] 10 | }, 11 | "nvika": { 12 | "version": "4.0.0", 13 | "commands": [ 14 | "nvika" 15 | ] 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Autodetect text files and ensure that we normalise their 2 | # line endings to lf internally. When checked out they may 3 | # use different line endings. 4 | * text=auto 5 | 6 | # Check out with crlf (Windows) line endings 7 | *.sln text eol=crlf 8 | *.csproj text eol=crlf 9 | *.cs text diff=csharp eol=crlf 10 | *.resx text eol=crlf 11 | *.vsixmanifest text eol=crlf 12 | packages.config text eol=crlf 13 | App.config text eol=crlf 14 | *.bat text eol=crlf 15 | *.cmd text eol=crlf 16 | *.snippet text eol=crlf 17 | *.manifest text eol=crlf 18 | *.licenseheader text eol=crlf 19 | 20 | # Check out with lf (UNIX) line endings 21 | *.sh text eol=lf 22 | .gitignore text eol=lf 23 | .gitattributes text eol=lf 24 | *.md text eol=lf 25 | .travis.yml text eol=lf -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug-report.yml: -------------------------------------------------------------------------------- 1 | name: Bug report 2 | description: Report an issue about the ruleset's performance, functionality, or visuals. 3 | body: 4 | - type: dropdown 5 | attributes: 6 | label: Branch 7 | options: 8 | - master 9 | - experimental 10 | validations: 11 | required: true 12 | 13 | - type: input 14 | attributes: 15 | label: Version 16 | description: Which version of the ruleset are you using? 17 | validations: 18 | required: true 19 | 20 | - type: textarea 21 | attributes: 22 | label: Describe the bug 23 | description: A clear and concise description of what the bug is. 24 | placeholder: | 25 | **Describe the bug** 26 | A clear and concise description of what the bug is. 27 | 28 | **To Reproduce** 29 | Steps to reproduce the behavior: 30 | 1. Go to '...' 31 | 2. Click on '....' 32 | 3. Scroll down to '....' 33 | 4. See error 34 | 35 | **Expected behavior** 36 | A clear and concise description of what you expected to happen. 37 | 38 | **Screenshots** 39 | If applicable, add screenshots to help explain your problem. 40 | validations: 41 | required: true 42 | 43 | - type: textarea 44 | attributes: 45 | label: Logs 46 | description: Drag and drop the log files into this box. 47 | validations: 48 | required: true 49 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: nuget 4 | directory: "/" 5 | schedule: 6 | interval: daily 7 | open-pull-requests-limit: 10 8 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Tagged Release 2 | on: 3 | push: 4 | tags: ['*'] 5 | 6 | jobs: 7 | build: 8 | name: Build and Create Release 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Fetch all tags 16 | run: git fetch --depth=1 origin +refs/tags/*:refs/tags/* 17 | 18 | - name: Get current tag 19 | run: echo "CURRENT_TAG=$(git describe --abbrev=0 --tags $(git rev-list --tags --max-count=1))" >> $GITHUB_ENV 20 | 21 | - name: Install dependencies 22 | run: dotnet restore 23 | 24 | - name: Build 25 | run: dotnet build osu.Game.Rulesets.Tau --configuration Release -p:version=${{env.CURRENT_TAG}} --no-restore 26 | 27 | - name: Create Release 28 | id: create_release 29 | uses: actions/create-release@latest 30 | env: 31 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 32 | with: 33 | tag_name: ${{ github.ref }} 34 | release_name: ${{ github.ref }} 35 | draft: true 36 | body: | 37 | # Installation: 38 | To install this ruleset just simply put this .DLL file onto your `osu/Rulesets` directory under `%appdata%`/. 39 | osu!lazer will do the rest for you. 40 | 41 | ## Localisation 42 | Localisations for this ruleset are available. If you want to help with translation efforts, please visit our [crowdin](https://crowdin.com/project/tau) page. 43 | 44 | ### Installing translations 45 | Download the `Localisations.zip` included in this release and extract it to the same place as you would place the tau DLL (`%appdata%/osu/Rulesets`). 46 | The file structure should look something like the following: 47 | 48 | - rulesets/ 49 | - ar/ 50 | - fr/ 51 | - .../ 52 | - osu.Game.Rulesets.Tau.dll 53 | 54 | --- 55 | 56 | Have a feature to suggest? Or encountered a bug? Or just want to chat with people interested in tau? [Join the discord server](https://discord.gg/GZ9R9vjFNW)! 57 | 58 | - name: Upload Release Asset 59 | id: upload-release-asset 60 | uses: actions/upload-release-asset@master 61 | env: 62 | GITHUB_TOKEN: ${{ secrets.RELEASE_TOKEN }} 63 | with: 64 | upload_url: ${{ steps.create_release.outputs.upload_url }} 65 | asset_path: ./osu.Game.Rulesets.Tau/bin/Release/net8.0/osu.Game.Rulesets.Tau.dll 66 | asset_name: osu.Game.Rulesets.Tau.dll 67 | asset_content_type: application/vnd.microsoft.portable-executable 68 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "Tau for osu! (Tests, Debug)", 6 | "type": "coreclr", 7 | "request": "launch", 8 | "program": "dotnet", 9 | "args": [ 10 | "${workspaceRoot}/osu.Game.Rulesets.Tau.Tests/bin/Debug/net8.0/osu.Game.Rulesets.Tau.Tests.dll" 11 | ], 12 | "cwd": "${workspaceRoot}", 13 | "preLaunchTask": "Build tests (Debug)", 14 | "console": "internalConsole" 15 | } 16 | ] 17 | } 18 | -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Build tests (Debug)", 6 | "type": "shell", 7 | "command": "dotnet", 8 | "args": [ 9 | "build", 10 | "--no-restore", 11 | "osu.Game.Rulesets.Tau.Tests", 12 | "/p:GenerateFullPaths=true", 13 | "/m", 14 | "/verbosity:m" 15 | ], 16 | "group": "build", 17 | "problemMatcher": "$msCompile" 18 | }, 19 | // Test Tasks 20 | { 21 | "label": "Run tests (Debug)", 22 | "type": "shell", 23 | "command": "dotnet", 24 | "args": [ 25 | "test", 26 | "/p:Configuration=Debug", 27 | ], 28 | "group": "test", 29 | "problemMatcher": "$msCompile" 30 | }, 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019-2020 Alten 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Conversion/TauConversionTestScene.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Objects; 6 | 7 | namespace osu.Game.Rulesets.Tau.Tests.Conversion 8 | { 9 | public abstract partial class TauConversionTestScene : TauModTestScene 10 | { 11 | protected abstract IEnumerable CreateHitObjects(); 12 | 13 | protected abstract void CreateAsserts(IEnumerable hitObjects); 14 | 15 | protected virtual bool PassCondition(IEnumerable hitObjects) 16 | => Player.Results.Count(r => r.IsHit) >= hitObjects.Count(); 17 | 18 | [Test] 19 | public void TestConversion() 20 | { 21 | var hitObjects = CreateHitObjects(); 22 | 23 | CreateModTest(new ModTestData 24 | { 25 | Autoplay = true, 26 | CreateBeatmap = () => new Beatmap 27 | { 28 | HitObjects = hitObjects.ToList() 29 | }, 30 | PassCondition = () => PassCondition(hitObjects) 31 | }); 32 | 33 | AddStep("Create converts asserts", () => 34 | { 35 | var beatmap = CreateBeatmap(Ruleset.Value); 36 | var converter = Ruleset.Value.CreateInstance().CreateBeatmapConverter(beatmap); 37 | var converted = converter.Convert(); 38 | 39 | CreateAsserts(converted.HitObjects); 40 | }); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Conversion/TestSceneBeatConversion.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Game.Rulesets.Objects; 4 | using osu.Game.Rulesets.Objects.Types; 5 | using osu.Game.Rulesets.Tau.Objects; 6 | using osuTK; 7 | 8 | namespace osu.Game.Rulesets.Tau.Tests.Conversion 9 | { 10 | public partial class TestSceneBeatConversion : TauConversionTestScene 11 | { 12 | protected override IEnumerable CreateHitObjects() 13 | { 14 | yield return new AngledHitObject { StartTime = 0, Angle = 90 }; 15 | yield return new PositionalHitObject { StartTime = 500, Position = new Vector2(257, 192) }; 16 | yield return new XPositionalHitObject { StartTime = 1000, X = 128 }; 17 | yield return new YPositionalHitObject { StartTime = 1500, Y = 96 }; 18 | } 19 | 20 | protected override void CreateAsserts(IEnumerable hitObjects) 21 | { 22 | AddAssert("Objects are of correct type", () => hitObjects.All(o => o is Beat)); 23 | var beats = hitObjects.Cast(); 24 | AddAssert("Beats are all correct angle", () => beats.All(b => b.Angle == 90)); 25 | } 26 | 27 | private class AngledHitObject : HitObject, IHasAngle 28 | { 29 | public float Angle { get; set; } 30 | } 31 | 32 | private class PositionalHitObject : HitObject, IHasPosition 33 | { 34 | public float X 35 | { 36 | get => Position.X; 37 | set => Position = new Vector2(value, Position.Y); 38 | } 39 | 40 | public float Y 41 | { 42 | get => Position.Y; 43 | set => Position = new Vector2(Position.X, value); 44 | } 45 | 46 | public Vector2 Position { get; set; } 47 | } 48 | 49 | private class XPositionalHitObject : HitObject, IHasXPosition 50 | { 51 | public float X { get; set; } 52 | } 53 | 54 | private class YPositionalHitObject : HitObject, IHasYPosition 55 | { 56 | public float Y { get; set; } 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Conversion/TestSceneHardBeatConversion.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Game.Audio; 4 | using osu.Game.Rulesets.Objects; 5 | using osu.Game.Rulesets.Tau.Objects; 6 | 7 | namespace osu.Game.Rulesets.Tau.Tests.Conversion 8 | { 9 | public partial class TestSceneHardBeatConversion : TauConversionTestScene 10 | { 11 | protected override IEnumerable CreateHitObjects() 12 | { 13 | yield return new HitObject { Samples = { new HitSampleInfo(HitSampleInfo.HIT_FINISH) } }; 14 | } 15 | 16 | protected override void CreateAsserts(IEnumerable hitObjects) 17 | { 18 | AddAssert("Hitobjects are of correct type", () => hitObjects.Any(o => o is HardBeat)); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Conversion/TestSceneSliderConversion.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Game.Audio; 4 | using osu.Game.Rulesets.Objects; 5 | using osu.Game.Rulesets.Objects.Types; 6 | using osu.Game.Rulesets.Tau.Beatmaps; 7 | using osu.Game.Rulesets.Tau.Objects; 8 | using osuTK; 9 | 10 | namespace osu.Game.Rulesets.Tau.Tests.Conversion 11 | { 12 | public partial class TestSceneSliderConversion : TauConversionTestScene 13 | { 14 | protected override IEnumerable CreateHitObjects() 15 | { 16 | yield return new ConvertSlider 17 | { 18 | Duration = 1000, 19 | Position = new Vector2(0), 20 | Path = new SliderPath(PathType.LINEAR, new[] { new Vector2(0, 10), new Vector2(255, 10) }), 21 | NodeSamples = { new List() } 22 | }; 23 | } 24 | 25 | protected override void CreateAsserts(IEnumerable hitObjects) 26 | { 27 | AddAssert("Hitobjects are of correct type", () => hitObjects.Any(o => o is Slider)); 28 | 29 | var slider = hitObjects.FirstOrDefault() as Slider; 30 | 31 | AddAssert("Slider is not null", () => slider != null); 32 | AddAssert("Slider has correct duration", () => slider!.Duration == 1000); 33 | 34 | var original = CreateHitObjects().FirstOrDefault() as ConvertSlider; 35 | 36 | AddAssert("Slider has correct starting angle", () => slider!.Angle == original.CurvePositionAt(0).GetHitObjectAngle()); 37 | AddAssert("Slider has correct ending angle", () => slider!.GetAbsoluteAngle(slider.Path.EndNode) == original.CurvePositionAt(1).GetHitObjectAngle()); 38 | } 39 | 40 | private class ConvertSlider : HitObject, IHasPathWithRepeats, IHasPosition 41 | { 42 | public double EndTime => StartTime + Duration; 43 | 44 | public double Duration { get; set; } 45 | 46 | public double Distance => Path.Distance; 47 | public SliderPath Path { get; set; } 48 | public int RepeatCount { get; set; } 49 | 50 | public IList> NodeSamples { get; } = new List>(); 51 | 52 | public float X 53 | { 54 | get => Position.X; 55 | set => Position = new Vector2(value, Position.Y); 56 | } 57 | 58 | public float Y 59 | { 60 | get => Position.Y; 61 | set => Position = new Vector2(Position.X, value); 62 | } 63 | 64 | public Vector2 Position { get; set; } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Conversion/TestSceneSpinnerConversion.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Game.Rulesets.Objects; 4 | using osu.Game.Rulesets.Objects.Types; 5 | using osu.Game.Rulesets.Tau.Objects; 6 | 7 | namespace osu.Game.Rulesets.Tau.Tests.Conversion 8 | { 9 | public partial class TestSceneSpinnerConversion : TauConversionTestScene 10 | { 11 | protected override IEnumerable CreateHitObjects() 12 | { 13 | yield return new DurationHitObject { Duration = 7500 }; 14 | } 15 | 16 | protected override void CreateAsserts(IEnumerable hitObjects) 17 | { 18 | AddAssert("Hitobjects are of correct type", () => hitObjects.Any(o => o is Slider)); 19 | 20 | var slider = hitObjects.FirstOrDefault() as Slider; 21 | 22 | AddAssert("Slider is not null", () => slider != null); 23 | AddAssert("Slider has correct duration", () => slider!.Duration == 7500); 24 | } 25 | 26 | private class DurationHitObject : HitObject, IHasDuration 27 | { 28 | public double EndTime => StartTime + Duration; 29 | public double Duration { get; set; } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneAutopilot.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneAutopilot : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutopilot() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneAutoplay.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Objects; 6 | using osu.Game.Rulesets.Tau.Objects; 7 | 8 | namespace osu.Game.Rulesets.Tau.Tests.Mods 9 | { 10 | public partial class TestSceneAutoplay : TauModTestScene 11 | { 12 | [Test] 13 | public void TestAutoplay() 14 | { 15 | CreateModTest(new ModTestData 16 | { 17 | Autoplay = true, 18 | CreateBeatmap = () => new Beatmap 19 | { 20 | HitObjects = new List 21 | { 22 | new Beat 23 | { 24 | StartTime = 500, 25 | Angle = 0 26 | }, 27 | new Slider 28 | { 29 | StartTime = 750, 30 | Path = new PolarSliderPath(new SliderNode[] 31 | { 32 | new(0, 0), 33 | new(50, -10), 34 | new(150, 10), 35 | }), 36 | RepeatCount = 1 37 | }, 38 | new HardBeat 39 | { 40 | StartTime = 1500 41 | } 42 | } 43 | }, 44 | PassCondition = () => Player.Results.Count(r => r.IsHit) >= 5, 45 | }); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneCinema.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneCinema : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModCinema() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneDoubleTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneDoubleTime : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModDoubleTime() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneDual.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using osu.Game.Rulesets.Mods; 3 | using osu.Game.Rulesets.Tau.Mods; 4 | using osu.Game.Rulesets.Tau.UI; 5 | using osu.Game.Tests.Visual; 6 | 7 | namespace osu.Game.Rulesets.Tau.Tests.Mods 8 | { 9 | public partial class TestSceneDual : TestSceneOsuPlayer 10 | { 11 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 12 | { 13 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModDual() }; 14 | return base.CreatePlayer(ruleset); 15 | } 16 | 17 | protected override bool HasCustomSteps => true; 18 | 19 | private TauPlayfield playfield; 20 | private TauCursor cursor; 21 | 22 | [Test] 23 | public void TestTraceableMod() 24 | { 25 | CreateTest(); 26 | 27 | AddStep("fetch playfield", () => { playfield = Player.DrawableRuleset.Playfield as TauPlayfield; }); 28 | AddAssert("playfield is not null", () => playfield != null); 29 | AddStep("fetch cursor", () => cursor = playfield.Cursor); 30 | AddAssert("cursor has additional paddles", () => cursor.AdditionalPaddles != null); 31 | AddAssert("cursor amount is correct", () => cursor.AdditionalPaddles!.Count == 1); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneEasy.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneEasy : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModEasy() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneFadeIn.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using osu.Framework.Testing; 4 | using osu.Game.Rulesets.Mods; 5 | using osu.Game.Rulesets.Tau.Mods; 6 | using osu.Game.Rulesets.Tau.UI; 7 | using osu.Game.Tests.Visual; 8 | 9 | namespace osu.Game.Rulesets.Tau.Tests.Mods 10 | { 11 | public partial class TestSceneFadeIn : TestSceneOsuPlayer 12 | { 13 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 14 | { 15 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModFadeIn() }; 16 | 17 | return base.CreatePlayer(ruleset); 18 | } 19 | 20 | protected override bool HasCustomSteps => true; 21 | 22 | [Test] 23 | public void TestFadeOutMod() 24 | { 25 | CreateTest(null); 26 | 27 | PlayfieldMaskingContainer pmc = null; 28 | 29 | AddAssert("Player has PMC", () => 30 | { 31 | var playfield = Player.DrawableRuleset.Playfield; 32 | var pmcs = playfield.ChildrenOfType(); 33 | 34 | if (!pmcs.Any()) 35 | return false; 36 | 37 | pmc = pmcs.First(); 38 | return true; 39 | }); 40 | 41 | AddAssert("pmc is of correct mode", () => pmc is { Mode: MaskingMode.FadeIn }); 42 | 43 | AddAssert("Positional effects are hidden", () => 44 | { 45 | var playfield = (TauPlayfield)Player.DrawableRuleset.Playfield; 46 | 47 | return !playfield.ShouldShowPositionalEffects.Value; 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneFadeOut.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using osu.Framework.Testing; 4 | using osu.Game.Rulesets.Mods; 5 | using osu.Game.Rulesets.Tau.Mods; 6 | using osu.Game.Rulesets.Tau.UI; 7 | using osu.Game.Tests.Visual; 8 | 9 | namespace osu.Game.Rulesets.Tau.Tests.Mods 10 | { 11 | public partial class TestSceneFadeOut : TestSceneOsuPlayer 12 | { 13 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 14 | { 15 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModFadeOut() }; 16 | 17 | return base.CreatePlayer(ruleset); 18 | } 19 | 20 | protected override bool HasCustomSteps => true; 21 | 22 | [Test] 23 | public void TestFadeOutMod() 24 | { 25 | CreateTest(); 26 | 27 | PlayfieldMaskingContainer pmc = null; 28 | 29 | AddAssert("Player has PMC", () => 30 | { 31 | var playfield = Player.DrawableRuleset.Playfield; 32 | var pmcs = playfield.ChildrenOfType(); 33 | 34 | if (!pmcs.Any()) 35 | return false; 36 | 37 | pmc = pmcs.First(); 38 | return true; 39 | }); 40 | 41 | AddAssert("pmc is of correct mode", () => pmc is { Mode: MaskingMode.FadeOut }); 42 | 43 | AddAssert("Positional effects are hidden", () => 44 | { 45 | var playfield = (TauPlayfield)Player.DrawableRuleset.Playfield; 46 | 47 | return !playfield.ShouldShowPositionalEffects.Value; 48 | }); 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneFlashlight.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneFlashlight : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModFlashlight() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneHalfTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneHalfTime : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModHalfTime() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneHardRock.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using NUnit.Framework; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Rulesets.Objects; 5 | using osu.Game.Rulesets.Tau.Mods; 6 | using osu.Game.Rulesets.Tau.Objects; 7 | 8 | namespace osu.Game.Rulesets.Tau.Tests.Mods 9 | { 10 | public partial class TestSceneHardRock : TauModTestScene 11 | { 12 | [Test] 13 | public void TestHardRock() 14 | { 15 | CreateModTest(new ModTestData() 16 | { 17 | Mod = new TauModHardRock(), 18 | CreateBeatmap = () => new Beatmap 19 | { 20 | HitObjects = new List 21 | { 22 | new Beat 23 | { 24 | StartTime = 500, 25 | Angle = 0 26 | }, 27 | new Beat 28 | { 29 | StartTime = 1000, 30 | Angle = 90 31 | }, 32 | new Beat 33 | { 34 | StartTime = 1500, 35 | Angle = 180 36 | }, 37 | new Beat 38 | { 39 | StartTime = 2000, 40 | Angle = 270 41 | } 42 | } 43 | }, 44 | PassCondition = () => 45 | { 46 | // ReSharper disable once ReplaceWithSingleAssignment.True 47 | var result = true; 48 | 49 | if (getBeat(0).Angle != 180) result = false; 50 | if (getBeat(1).Angle != 270) result = false; 51 | if (getBeat(2).Angle != 0) result = false; 52 | if (getBeat(3).Angle != 90) result = false; 53 | 54 | return result; 55 | } 56 | }); 57 | } 58 | 59 | private Beat getBeat(int index) 60 | => Beatmap.Value.Beatmap.HitObjects[index] as Beat; 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneInverse.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneInverse : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModInverse() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneNightcore.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneNightcore : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModNightcore() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestScenePerfect.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestScenePerfect : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModPerfect() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneRelax.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneRelax : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModRelax() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneShowoff.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Objects; 6 | using osu.Game.Rulesets.Tau.Mods; 7 | using osu.Game.Rulesets.Tau.Objects; 8 | 9 | namespace osu.Game.Rulesets.Tau.Tests.Mods 10 | { 11 | public partial class TestSceneShowoff : TauModTestScene 12 | { 13 | [Test] 14 | public void TestAutoplay() 15 | { 16 | CreateModTest(new ModTestData 17 | { 18 | Autoplay = false, 19 | Mod = new TauModShowoffAutoplay(), 20 | CreateBeatmap = () => new Beatmap 21 | { 22 | HitObjects = new List 23 | { 24 | new Beat 25 | { 26 | StartTime = 500, 27 | Angle = 0 28 | }, 29 | new Slider 30 | { 31 | StartTime = 750, 32 | Path = new PolarSliderPath(new SliderNode[] 33 | { 34 | new(0, 0), 35 | new(50, -10), 36 | new(150, 10), 37 | }), 38 | RepeatCount = 1 39 | }, 40 | new HardBeat 41 | { 42 | StartTime = 1500 43 | } 44 | } 45 | }, 46 | PassCondition = () => Player.Results.Count(r => r.IsHit) >= 5, 47 | }); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneSuddenDeath.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Mods; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests.Mods 6 | { 7 | public partial class TestSceneSuddenDeath : TestSceneOsuPlayer 8 | { 9 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 10 | { 11 | SelectedMods.Value = new Mod[] { new TauModSuddenDeath() }; 12 | 13 | return base.CreatePlayer(ruleset); 14 | } 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Mods/TestSceneTraceable.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using osu.Game.Rulesets.Mods; 3 | using osu.Game.Rulesets.Tau.Mods; 4 | using osu.Game.Rulesets.Tau.UI; 5 | using osu.Game.Tests.Visual; 6 | 7 | namespace osu.Game.Rulesets.Tau.Tests.Mods 8 | { 9 | public partial class TestSceneTraceable : TestSceneOsuPlayer 10 | { 11 | protected override TestPlayer CreatePlayer(Ruleset ruleset) 12 | { 13 | SelectedMods.Value = new Mod[] { new TauModAutoplay(), new TauModTraceable() }; 14 | return base.CreatePlayer(ruleset); 15 | } 16 | 17 | protected override bool HasCustomSteps => true; 18 | 19 | private TauPlayfield playfield; 20 | 21 | [Test] 22 | public void TestTraceableMod() 23 | { 24 | CreateTest(); 25 | 26 | AddStep("fetch playfield", () => { playfield = Player.DrawableRuleset.Playfield as TauPlayfield; }); 27 | AddAssert("playfield is invisible", () => playfield.PlayfieldPiece.Alpha == 0); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Objects/TestSceneAutoplayBeat.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using NUnit.Framework; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Objects; 6 | using osu.Game.Rulesets.Tau.Mods; 7 | using osu.Game.Rulesets.Tau.Objects; 8 | 9 | namespace osu.Game.Rulesets.Tau.Tests.Objects 10 | { 11 | public partial class TestSceneAutoplayBeat : TauModTestScene 12 | { 13 | [TestCase(2000, 4)] 14 | [TestCase(2000, 8)] 15 | [TestCase(2000, 12)] 16 | [TestCase(2000, 24)] 17 | [TestCase(1000, 4)] 18 | [TestCase(1000, 8)] 19 | [TestCase(1000, 12)] 20 | [TestCase(1000, 24)] 21 | [TestCase(500, 4)] 22 | [TestCase(500, 8)] 23 | [TestCase(500, 12)] 24 | [TestCase(500, 24)] 25 | public void TestAutoplay(float duration, int amount) 26 | { 27 | var hitObjects = new List(); 28 | var angleDelta = 360f / amount; 29 | var timeDelta = duration / amount; 30 | 31 | for (int i = 0; i < amount; i++) 32 | { 33 | hitObjects.Add(new Beat 34 | { 35 | StartTime = 1000 + (timeDelta * i), 36 | Angle = angleDelta * i 37 | }); 38 | } 39 | 40 | CreateModTest(new ModTestData 41 | { 42 | Autoplay = false, 43 | Mod = new TauModAutoplay(), 44 | CreateBeatmap = () => new Beatmap 45 | { 46 | HitObjects = hitObjects 47 | }, 48 | PassCondition = () => Player.Results.Count(r => r.IsHit) >= amount, 49 | }); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/Objects/TestSceneHardBeat.cs: -------------------------------------------------------------------------------- 1 | using System.Linq; 2 | using NUnit.Framework; 3 | using osu.Framework.Graphics; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Beatmaps.ControlPoints; 6 | using osu.Game.Rulesets.Scoring; 7 | using osu.Game.Rulesets.Tau.Objects; 8 | using osu.Game.Rulesets.Tau.Objects.Drawables; 9 | using osu.Game.Rulesets.Tau.UI; 10 | 11 | namespace osu.Game.Rulesets.Tau.Tests.Objects 12 | { 13 | [TestFixture] 14 | public partial class TestSceneHardBeat : TauTestScene 15 | { 16 | private int depthIndex; 17 | 18 | public TestSceneHardBeat() 19 | { 20 | TauPlayfieldAdjustmentContainer container; 21 | Add(container = new TauPlayfieldAdjustmentContainer()); 22 | 23 | AddStep("Miss single", () => container.Child = testSingle()); 24 | AddStep("Hit single", () => container.Child = testSingle(true)); 25 | AddUntilStep("Wait for object despawn", () => !Children.Any(h => h is DrawableHardBeat { AllJudged: false })); 26 | } 27 | 28 | private Drawable testSingle(bool auto = false) 29 | { 30 | var circle = new HardBeat 31 | { 32 | StartTime = Time.Current + 1000, 33 | }; 34 | 35 | circle.ApplyDefaults(new ControlPointInfo(), new BeatmapDifficulty()); 36 | 37 | return new TestDrawableHardBeat(circle, auto) 38 | { 39 | Anchor = Anchor.Centre, 40 | Origin = Anchor.Centre, 41 | Depth = depthIndex++, 42 | }; 43 | } 44 | 45 | private partial class TestDrawableHardBeat : DrawableHardBeat 46 | { 47 | private readonly bool auto; 48 | 49 | public TestDrawableHardBeat(HardBeat h, bool auto) 50 | : base(h) 51 | { 52 | this.auto = auto; 53 | } 54 | 55 | protected override void CheckForResult(bool userTriggered, double timeOffset) 56 | { 57 | if (auto && !userTriggered && timeOffset > 0) 58 | { 59 | // force success 60 | ApplyResult(HitResult.Great); 61 | } 62 | else 63 | base.CheckForResult(userTriggered, timeOffset); 64 | } 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TauModTestScene.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Tests.Visual; 2 | 3 | namespace osu.Game.Rulesets.Tau.Tests 4 | { 5 | public abstract partial class TauModTestScene : ModTestScene 6 | { 7 | protected override Ruleset CreatePlayerRuleset() => new TauRuleset(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TauSkinnableTestScene.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Containers; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests 6 | { 7 | public partial class TauSkinnableTestScene : SkinnableTestScene 8 | { 9 | private Container content; 10 | 11 | protected override Container Content 12 | { 13 | get 14 | { 15 | if (content == null) 16 | base.Content.Add(content = new TauInputManager(new TauRuleset().RulesetInfo)); 17 | 18 | return content; 19 | } 20 | } 21 | 22 | protected override Ruleset CreateRulesetForSkinProvider() => new TauRuleset(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TauTestScene.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Game.Rulesets.Tau.UI; 3 | using osu.Game.Tests.Visual; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests 6 | { 7 | public abstract partial class TauTestScene : OsuTestScene 8 | { 9 | [Cached] 10 | private TauCachedProperties properties { get; set; } = new(); 11 | 12 | protected TauCachedProperties Properties => properties; 13 | 14 | protected override void Dispose(bool isDisposing) 15 | { 16 | base.Dispose(isDisposing); 17 | properties.Dispose(); 18 | } 19 | 20 | protected override Ruleset CreateRuleset() 21 | => new TauRuleset(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneClassicKiai.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Tau.UI.Effects; 2 | 3 | namespace osu.Game.Rulesets.Tau.Tests 4 | { 5 | public partial class TestSceneClassicKiai : TestSceneKiaiEffects 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneKiaiEffects.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Testing; 4 | using osu.Game.Rulesets.Judgements; 5 | using osu.Game.Rulesets.Scoring; 6 | using osu.Game.Rulesets.Tau.Judgements; 7 | using osu.Game.Rulesets.Tau.Objects; 8 | using osu.Game.Rulesets.Tau.Objects.Drawables; 9 | using osu.Game.Rulesets.Tau.UI; 10 | using osu.Game.Rulesets.Tau.UI.Effects; 11 | 12 | namespace osu.Game.Rulesets.Tau.Tests 13 | { 14 | public abstract partial class TestSceneKiaiEffects : TauTestScene 15 | where T : KiaiEffect, new() 16 | where TEmitter : Emitter, new() 17 | { 18 | protected T KiaiContainer; 19 | 20 | protected virtual void AddExtraSetupSteps() 21 | { 22 | } 23 | 24 | [SetUpSteps] 25 | public void SetUp() 26 | { 27 | AddStep("Clear contents", Clear); 28 | AddStep("Add contents", () => Add(new TauPlayfieldAdjustmentContainer 29 | { 30 | Children = new Drawable[] 31 | { 32 | new TauPlayfield(), 33 | KiaiContainer = new T() 34 | } 35 | })); 36 | 37 | AddExtraSetupSteps(); 38 | } 39 | 40 | [TestCase(false)] 41 | [TestCase(true)] 42 | public void TestEffect(bool isInversed) 43 | { 44 | AddStep("Set inverse effect", () => 45 | { 46 | Properties.InverseModEnabled.Value = isInversed; 47 | }); 48 | 49 | AddStep("Add beat result", 50 | () => KiaiContainer.OnNewResult( 51 | new DrawableBeat(new Beat()), new JudgementResult(new Beat(), new TauJudgement()) { Type = HitResult.Great })); 52 | 53 | AddStep("Add hard beat result", 54 | () => KiaiContainer.OnNewResult( 55 | new DrawableHardBeat(new HardBeat()), new JudgementResult(new HardBeat(), new TauJudgement()) { Type = HitResult.Great })); 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneOsuGame.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Game.Tests.Visual; 3 | 4 | namespace osu.Game.Rulesets.Tau.Tests 5 | { 6 | public partial class TestSceneOsuGame : OsuTestScene 7 | { 8 | [BackgroundDependencyLoader] 9 | private void load() 10 | { 11 | AddGame(new OsuGame()); 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneOsuPlayer.cs: -------------------------------------------------------------------------------- 1 | using NUnit.Framework; 2 | using osu.Game.Tests.Visual; 3 | 4 | namespace osu.Game.Rulesets.Tau.Tests 5 | { 6 | [TestFixture] 7 | public partial class TestSceneOsuPlayer : PlayerTestScene 8 | { 9 | protected override Ruleset CreatePlayerRuleset() => new TauRuleset(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneResumeOverlay.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Graphics.Containers; 4 | using osu.Game.Rulesets.Tau.UI; 5 | using osu.Game.Rulesets.UI; 6 | using osu.Game.Screens.Play; 7 | using osu.Game.Tests.Visual; 8 | 9 | namespace osu.Game.Rulesets.Tau.Tests 10 | { 11 | public partial class TestSceneResumeOverlay : OsuManualInputManagerTestScene 12 | { 13 | [Cached] 14 | private TauCachedProperties properties { get; set; } = new(); 15 | 16 | public TestSceneResumeOverlay() 17 | { 18 | ManualTauInputManager tauInputManager; 19 | GameplayCursorContainer cursor; 20 | ResumeOverlay resume; 21 | 22 | bool resumeFired = false; 23 | 24 | Child = tauInputManager = new ManualTauInputManager(new TauRuleset().RulesetInfo) 25 | { 26 | Children = new Drawable[] 27 | { 28 | cursor = new GameplayCursorContainer(), 29 | resume = new TauResumeOverlay() 30 | { 31 | GameplayCursor = cursor 32 | } 33 | } 34 | }; 35 | 36 | resume.ResumeAction = () => resumeFired = true; 37 | 38 | AddStep("move mouse to center", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.TopLeft)); 39 | AddStep("show", () => resume.Show()); 40 | 41 | AddStep("move mouse away", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.BottomRight)); 42 | AddStep("click", () => tauInputManager.GameClick()); 43 | AddAssert("not dismissed", () => !resumeFired && resume.State.Value == Visibility.Visible); 44 | 45 | AddStep("move mouse back", () => InputManager.MoveMouseTo(ScreenSpaceDrawQuad.TopLeft)); 46 | AddStep("click", () => tauInputManager.GameClick()); 47 | AddAssert("dismissed", () => resumeFired && resume.State.Value == Visibility.Hidden); 48 | } 49 | 50 | private partial class ManualTauInputManager : TauInputManager 51 | { 52 | public ManualTauInputManager(RulesetInfo ruleset) 53 | : base(ruleset) 54 | { 55 | } 56 | 57 | public void GameClick() 58 | { 59 | KeyBindingContainer.TriggerPressed(TauAction.LeftButton); 60 | KeyBindingContainer.TriggerReleased(TauAction.LeftButton); 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneTauCursor.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Tau.UI; 2 | using osu.Game.Tests.Visual; 3 | using osuTK; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests 6 | { 7 | public partial class TestSceneTauCursor : OsuManualInputManagerTestScene 8 | { 9 | public TestSceneTauCursor() 10 | { 11 | TauCursor cursor; 12 | Add(cursor = new TauCursor()); 13 | 14 | AddStep("Reset cursor", () => { InputManager.MoveMouseTo(cursor, new Vector2(0, -50)); }); 15 | AddStep("Hide paddle", () => { cursor.Hide(); }); 16 | AddStep("Show paddle", () => { cursor.Show(); }); 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneTauPlayfield.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Shapes; 3 | using osu.Game.Rulesets.Tau.UI; 4 | using osuTK.Graphics; 5 | 6 | namespace osu.Game.Rulesets.Tau.Tests 7 | { 8 | public partial class TestSceneTauPlayfield : TauTestScene 9 | { 10 | public TestSceneTauPlayfield() 11 | { 12 | Add(new TauPlayfieldAdjustmentContainer 13 | { 14 | Children = new Drawable[] 15 | { 16 | new Box 17 | { 18 | Colour = Color4.Red, 19 | Alpha = 0.2f, 20 | RelativeSizeAxes = Axes.Both 21 | }, 22 | new TauPlayfield() 23 | } 24 | }); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneTurbulenceKiai.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Tau.UI; 2 | using osu.Game.Rulesets.Tau.UI.Effects; 3 | using osuTK; 4 | 5 | namespace osu.Game.Rulesets.Tau.Tests 6 | { 7 | public partial class TestSceneTurbulenceKiai : TestSceneKiaiEffects 8 | { 9 | protected override void AddExtraSetupSteps() 10 | { 11 | AddStep("Add turbulence", () => 12 | { 13 | KiaiContainer.Vortices.Add(new Vortex 14 | { 15 | Position = new Vector2(0, -((TauPlayfield.BASE_SIZE.X / 2) + 105)), 16 | Velocity = new Vector2(10), 17 | Scale = 0.01f, 18 | Speed = 5f, 19 | }); 20 | }); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/TestSceneVisualizer.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Extensions.Color4Extensions; 2 | using osu.Framework.Graphics; 3 | using osu.Game.Rulesets.Tau.Objects; 4 | using osu.Game.Rulesets.Tau.Objects.Drawables; 5 | using osu.Game.Rulesets.Tau.UI; 6 | using osu.Game.Rulesets.Tau.UI.Effects; 7 | using osu.Game.Tests.Visual; 8 | using osuTK.Graphics; 9 | 10 | namespace osu.Game.Rulesets.Tau.Tests 11 | { 12 | public partial class TestSceneVisualizer : OsuTestScene 13 | { 14 | public TestSceneVisualizer() 15 | { 16 | PlayfieldVisualizer visualizer; 17 | Add(new TauPlayfieldAdjustmentContainer 18 | { 19 | Child = visualizer = new PlayfieldVisualizer 20 | { 21 | AccentColour = Color4.White.Opacity(0.25f) 22 | } 23 | }); 24 | 25 | AddStep("Show visualizer", () => visualizer.FadeIn()); 26 | 27 | AddStep("Beat hit", () => visualizer.OnNewResult(new DrawableBeat(new Beat()))); 28 | AddStep("Hard beat hit", () => visualizer.OnNewResult(new DrawableHardBeat(new HardBeat()))); 29 | AddStep("Slider hit", () => visualizer.UpdateAmplitudes(0f, 0.15f)); 30 | } 31 | 32 | protected override Ruleset CreateRuleset() 33 | => new TauRuleset(); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/VisualTestRunner.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework; 3 | using osu.Framework.Platform; 4 | using osu.Game.Tests; 5 | 6 | namespace osu.Game.Rulesets.Tau.Tests 7 | { 8 | public static class VisualTestRunner 9 | { 10 | [STAThread] 11 | public static int Main(string[] args) 12 | { 13 | using DesktopGameHost host = Host.GetSuitableDesktopHost(@"osu"); 14 | host.Run(new OsuTestBrowser()); 15 | 16 | return 0; 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau.Tests/osu.Game.Rulesets.Tau.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | osu.Game.Rulesets.Tau.Tests.VisualTestRunner 4 | default 5 | 6 | 7 | 8 | 9 | 10 | false 11 | osu.Game.Rulesets.Tau.Tests 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Exe 24 | net8.0 25 | osu.Game.Rulesets.Tau.Tests 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Allocation/MemoryPool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers; 3 | using System.Collections.Generic; 4 | using System.Diagnostics; 5 | 6 | namespace osu.Game.Rulesets.Tau.Allocation 7 | { 8 | /// 9 | /// Wrapper for which returns 10 | /// and an optional rented or . 11 | /// 12 | /// 13 | /// 14 | /// using (MemoryPool<T>.Shared.Rent(100, out Span<T> span)) { ... } 15 | /// 16 | /// 17 | /// 18 | public class MemoryPool 19 | { 20 | private readonly ArrayPool backing; 21 | 22 | public MemoryPool(ArrayPool backing) 23 | { 24 | this.backing = backing; 25 | } 26 | 27 | public static MemoryPool Shared { get; } = new(ArrayPool.Shared); 28 | 29 | public RentedArray Rent(ICollection value) 30 | { 31 | var arr = backing.Rent(value.Count); 32 | value.CopyTo(arr, 0); 33 | return new RentedArray(backing, arr, value.Count); 34 | } 35 | 36 | public RentedArray Rent(int size) 37 | => new(backing, backing.Rent(size), size); 38 | } 39 | 40 | public struct RentedArray : IDisposable 41 | { 42 | private readonly ArrayPool backing; 43 | private readonly T[] rented; 44 | public readonly int Length; 45 | 46 | public RentedArray(ArrayPool backing, T[] rented, int length) 47 | { 48 | this.backing = backing; 49 | this.rented = rented; 50 | Length = length; 51 | Debug.Assert(length <= rented.Length, $"Requested length ({length}) must be <= rented array's length ({rented.Length})"); 52 | } 53 | 54 | public IEnumerator GetEnumerator() 55 | { 56 | for (int i = 0; i < Length; ++i) 57 | yield return rented[i]; 58 | } 59 | 60 | public ref T this[int i] => ref rented[i]; 61 | public ref T this[Index i] => ref rented[i]; 62 | 63 | public void Dispose() 64 | { 65 | backing?.Return(rented); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Beatmaps/TauBeatmap.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Framework.Graphics.Sprites; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Tau.Localisation; 6 | using osu.Game.Rulesets.Tau.Objects; 7 | using osuTK; 8 | 9 | namespace osu.Game.Rulesets.Tau.Beatmaps 10 | { 11 | public class TauBeatmap : Beatmap 12 | { 13 | public override IEnumerable GetStatistics() 14 | { 15 | int beats = HitObjects.Count(c => c is Beat); 16 | int sliders = HitObjects.Count(s => s is Slider); 17 | int hardBeats = HitObjects.Count(hb => hb is HardBeat); 18 | 19 | return new[] 20 | { 21 | new BeatmapStatistic 22 | { 23 | Name = BeatmapStrings.BeatCount, 24 | Content = beats.ToString(), 25 | CreateIcon = () => new SpriteIcon 26 | { 27 | Icon = FontAwesome.Solid.Square, 28 | Scale = new Vector2(.7f) 29 | }, 30 | }, 31 | new BeatmapStatistic 32 | { 33 | Name = BeatmapStrings.SliderCount, 34 | Content = sliders.ToString(), 35 | CreateIcon = () => new BeatmapStatisticIcon(BeatmapStatisticsIconType.Sliders) 36 | }, 37 | new BeatmapStatistic 38 | { 39 | Name = BeatmapStrings.HardBeatCount, 40 | Content = hardBeats.ToString(), 41 | CreateIcon = () => new SpriteIcon 42 | { 43 | Icon = FontAwesome.Regular.Circle, 44 | Scale = new Vector2(.7f) 45 | }, 46 | } 47 | }; 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Configuration/KiaiType.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | using osu.Game.Rulesets.Tau.Localisation; 3 | 4 | namespace osu.Game.Rulesets.Tau.Configuration 5 | { 6 | public enum KiaiType 7 | { 8 | [LocalisableDescription(typeof(KiaiTypeStrings), nameof(KiaiTypeStrings.Turbulence))] 9 | Turbulence, 10 | 11 | [LocalisableDescription(typeof(KiaiTypeStrings), nameof(KiaiTypeStrings.Classic))] 12 | Classic, 13 | 14 | [LocalisableDescription(typeof(KiaiTypeStrings), nameof(KiaiTypeStrings.None))] 15 | None 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Configuration/TauRulesetConfigManager.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Configuration; 2 | using osu.Game.Rulesets.Configuration; 3 | 4 | namespace osu.Game.Rulesets.Tau.Configuration 5 | { 6 | public class TauRulesetConfigManager : RulesetConfigManager 7 | { 8 | public TauRulesetConfigManager(SettingsStore settings, RulesetInfo ruleset, int? variant = null) 9 | : base(settings, ruleset, variant) 10 | { 11 | } 12 | 13 | protected override void InitialiseDefaults() 14 | { 15 | base.InitialiseDefaults(); 16 | 17 | SetDefault(TauRulesetSettings.ShowEffects, true); 18 | SetDefault(TauRulesetSettings.ShowVisualizer, true); 19 | SetDefault(TauRulesetSettings.ShowSliderEffects, true); 20 | SetDefault(TauRulesetSettings.HitLighting, false); 21 | SetDefault(TauRulesetSettings.KiaiType, KiaiType.Turbulence); 22 | SetDefault(TauRulesetSettings.PlayfieldDim, 0.7f, 0, 1, 0.01f); 23 | SetDefault(TauRulesetSettings.NotesSize, 16f, 10, 25, 1f); 24 | } 25 | } 26 | 27 | public enum TauRulesetSettings 28 | { 29 | ShowEffects, 30 | ShowVisualizer, 31 | ShowSliderEffects, // There's no real reason to have a toggle for showing Kiai effects, as that's already handled under KiaiType 32 | HitLighting, 33 | KiaiType, 34 | PlayfieldDim, 35 | NotesSize, 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/Preprocessing/TauDifficultyHitObject.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using osu.Game.Rulesets.Difficulty.Preprocessing; 4 | using osu.Game.Rulesets.Objects; 5 | using osu.Game.Rulesets.Tau.Objects; 6 | 7 | namespace osu.Game.Rulesets.Tau.Difficulty.Preprocessing 8 | { 9 | public class TauDifficultyHitObject : DifficultyHitObject 10 | { 11 | private const int min_delta_time = 25; 12 | 13 | public new TauHitObject BaseObject => (TauHitObject)base.BaseObject; 14 | 15 | /// 16 | /// Milliseconds elapsed since the start time of the previous , with a minimum of 25ms. 17 | /// 18 | public double StrainTime; 19 | 20 | public TauDifficultyHitObject(HitObject hitObject, HitObject lastObject, double clockRate, List objects, int index) 21 | : base(hitObject, lastObject, clockRate, objects, index) 22 | { 23 | // Capped to 25ms to prevent difficulty calculation breaking from simultaneous objects. 24 | StrainTime = Math.Max(DeltaTime, min_delta_time); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/Skills/Aim.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Game.Rulesets.Difficulty.Preprocessing; 3 | using osu.Game.Rulesets.Difficulty.Skills; 4 | using osu.Game.Rulesets.Mods; 5 | using osu.Game.Rulesets.Tau.Difficulty.Evaluators; 6 | using osu.Game.Rulesets.Tau.Difficulty.Preprocessing; 7 | 8 | namespace osu.Game.Rulesets.Tau.Difficulty.Skills 9 | { 10 | public class Aim : StrainDecaySkill 11 | { 12 | private readonly Type[] allowedHitObjects; 13 | 14 | protected override double SkillMultiplier => 7.4; 15 | protected override double StrainDecayBase => 0.25; 16 | 17 | public Aim(Mod[] mods, Type[] allowedHitObjects) 18 | : base(mods) 19 | { 20 | this.allowedHitObjects = allowedHitObjects; 21 | } 22 | 23 | protected override double StrainValueOf(DifficultyHitObject current) 24 | { 25 | if (current.Index <= 1 || current is not TauAngledDifficultyHitObject tauCurrObj || tauCurrObj.LastAngled == null) 26 | return 0; 27 | 28 | if (tauCurrObj.Distance < tauCurrObj.AngleRange) 29 | return 0; 30 | 31 | return AimEvaluator.EvaluateDifficulty(tauCurrObj, tauCurrObj.LastAngled, allowedHitObjects); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/Skills/Complexity.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Difficulty.Preprocessing; 2 | using osu.Game.Rulesets.Difficulty.Skills; 3 | using osu.Game.Rulesets.Mods; 4 | using osu.Game.Rulesets.Tau.Difficulty.Evaluators; 5 | 6 | namespace osu.Game.Rulesets.Tau.Difficulty.Skills 7 | { 8 | public class Complexity : StrainDecaySkill 9 | { 10 | protected override double SkillMultiplier => 60; 11 | 12 | protected override double StrainDecayBase => 0.35; 13 | 14 | public Complexity(Mod[] mods) 15 | : base(mods) 16 | { 17 | } 18 | 19 | protected override double StrainValueOf(DifficultyHitObject current) 20 | => ComplexityEvaluator.EvaluateDifficulty(current); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/Skills/Speed.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Game.Rulesets.Difficulty.Preprocessing; 3 | using osu.Game.Rulesets.Mods; 4 | using osu.Game.Rulesets.Tau.Difficulty.Evaluators; 5 | 6 | namespace osu.Game.Rulesets.Tau.Difficulty.Skills 7 | { 8 | public class Speed : TauStrainSkill 9 | { 10 | private const double skill_multiplier = 515; 11 | private const double strain_decay_base = 0.3; 12 | 13 | private readonly double greatWindow; 14 | 15 | private double currentStrain; 16 | private double currentRhythm; 17 | 18 | protected override int ReducedSectionCount => 5; 19 | protected override double DifficultyMultiplier => 1.37; 20 | 21 | public Speed(Mod[] mods, double hitWindowGreat) 22 | : base(mods) 23 | { 24 | greatWindow = hitWindowGreat; 25 | } 26 | 27 | protected override double StrainValueAt(DifficultyHitObject current) 28 | { 29 | currentStrain *= strainDecay(current.DeltaTime); 30 | currentStrain += SpeedEvaluator.EvaluateDifficulty(current, greatWindow) * skill_multiplier; 31 | 32 | currentRhythm = RhythmEvaluator.EvaluateDifficulty(current, greatWindow); 33 | 34 | return currentStrain * currentRhythm; 35 | } 36 | 37 | protected override double CalculateInitialStrain(double time, DifficultyHitObject current) 38 | => (currentStrain * currentRhythm) * strainDecay(time - current.Previous(0).StartTime); 39 | 40 | private double strainDecay(double ms) => Math.Pow(strain_decay_base, ms / 1000); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/Skills/TauStrainSkill.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using osu.Game.Rulesets.Difficulty.Skills; 4 | using osu.Game.Rulesets.Mods; 5 | using System.Linq; 6 | using osu.Framework.Utils; 7 | 8 | namespace osu.Game.Rulesets.Tau.Difficulty.Skills 9 | { 10 | public abstract class TauStrainSkill : StrainSkill 11 | { 12 | /// 13 | /// The number of sections with the highest strains, which the peak strain reductions will apply to. 14 | /// This is done in order to decrease their impact on the overall difficulty of the map for this skill. 15 | /// 16 | protected virtual int ReducedSectionCount => 10; 17 | 18 | /// 19 | /// The baseline multiplier applied to the section with the biggest strain. 20 | /// 21 | protected virtual double ReducedStrainBaseline => 0.75; 22 | 23 | /// 24 | /// The final multiplier to be applied to after all other calculations. 25 | /// 26 | protected virtual double DifficultyMultiplier => 1.06; 27 | 28 | protected TauStrainSkill(Mod[] mods) 29 | : base(mods) 30 | { 31 | } 32 | 33 | public override double DifficultyValue() 34 | { 35 | double difficulty = 0; 36 | double weight = 1; 37 | 38 | // Sections with 0 strain are excluded to avoid worst-case time complexity of the following sort (e.g. /b/2351871). 39 | // These sections will not contribute to the difficulty. 40 | var peaks = GetCurrentStrainPeaks().Where(p => p > 0); 41 | 42 | List strains = peaks.OrderByDescending(d => d).ToList(); 43 | 44 | // We are reducing the highest strains first to account for extreme difficulty spikes 45 | for (int i = 0; i < Math.Min(strains.Count, ReducedSectionCount); i++) 46 | { 47 | double scale = Math.Log10(Interpolation.Lerp(1, 10, Math.Clamp((float)i / ReducedSectionCount, 0, 1))); 48 | strains[i] *= Interpolation.Lerp(ReducedStrainBaseline, 1.0, scale); 49 | } 50 | 51 | // Difficulty is the weighted sum of the highest strains from every section. 52 | // We're sorting from highest to lowest strain. 53 | foreach (double strain in strains.OrderByDescending(d => d)) 54 | { 55 | difficulty += strain * weight; 56 | weight *= DecayWeight; 57 | } 58 | 59 | return difficulty * DifficultyMultiplier; 60 | } 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/TauDifficultyAttributes.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using osu.Game.Rulesets.Difficulty; 3 | 4 | namespace osu.Game.Rulesets.Tau.Difficulty 5 | { 6 | public class TauDifficultyAttributes : DifficultyAttributes 7 | { 8 | [JsonProperty("aim_difficulty")] 9 | public double AimDifficulty { get; set; } 10 | 11 | [JsonProperty("speed_difficulty")] 12 | public double SpeedDifficulty { get; set; } 13 | 14 | [JsonProperty("complexity_difficulty")] 15 | public double ComplexityDifficulty { get; set; } 16 | 17 | /// 18 | /// The perceived approach rate inclusive of rate-adjusting mods (DT/HT/etc). 19 | /// 20 | /// 21 | /// Rate-adjusting mods don't directly affect the approach rate difficulty value, but have a perceived effect as a result of adjusting audio timing. 22 | /// 23 | [JsonProperty("approach_rate")] 24 | public double ApproachRate { get; set; } 25 | 26 | /// 27 | /// Describes how much of is contributed to by hitcircles or sliders. 28 | /// A value closer to 1.0 indicates most of is contributed by hitcircles. 29 | /// A value closer to 0.0 indicates most of is contributed by sliders. 30 | /// 31 | [JsonProperty("slider_factor")] 32 | public double SliderFactor { get; set; } 33 | 34 | /// 35 | /// The perceived overall difficulty inclusive of rate-adjusting mods (DT/HT/etc). 36 | /// 37 | /// 38 | /// Rate-adjusting mods don't directly affect the overall difficulty value, but have a perceived effect as a result of adjusting audio timing. 39 | /// 40 | [JsonProperty("overall_difficulty")] 41 | public double OverallDifficulty { get; set; } 42 | 43 | /// 44 | /// The beatmap's drain rate. This doesn't scale with rate-adjusting mods. 45 | /// 46 | public double DrainRate { get; set; } 47 | 48 | /// 49 | /// The number of regular beats in the beatmap. 50 | /// 51 | public int NotesCount { get; set; } 52 | 53 | /// 54 | /// The number of sliders in the beatmap. 55 | /// 56 | public int SliderCount { get; set; } 57 | 58 | /// 59 | /// The number of hard beats in the beatmap. 60 | /// 61 | public int HardBeatCount { get; set; } 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Difficulty/TauPerformanceAttribute.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using Newtonsoft.Json; 3 | using osu.Game.Rulesets.Difficulty; 4 | 5 | namespace osu.Game.Rulesets.Tau.Difficulty 6 | { 7 | public class TauPerformanceAttribute : PerformanceAttributes 8 | { 9 | [JsonProperty("aim")] 10 | public double Aim { get; set; } 11 | 12 | [JsonProperty("speed")] 13 | public double Speed { get; set; } 14 | 15 | [JsonProperty("accuracy")] 16 | public double Accuracy { get; set; } 17 | 18 | [JsonProperty("complexity")] 19 | public double Complexity { get; set; } 20 | 21 | [JsonProperty("effective_miss_count")] 22 | public double EffectiveMissCount { get; set; } 23 | 24 | public override IEnumerable GetAttributesForDisplay() 25 | { 26 | foreach (var attribute in base.GetAttributesForDisplay()) 27 | { 28 | yield return attribute; 29 | } 30 | 31 | yield return new PerformanceDisplayAttribute(nameof(Aim), "Aim", Aim); 32 | yield return new PerformanceDisplayAttribute(nameof(Accuracy), "Accuracy", Accuracy); 33 | yield return new PerformanceDisplayAttribute(nameof(Speed), "Speed", Speed); 34 | yield return new PerformanceDisplayAttribute(nameof(Complexity), "Complexity", Complexity); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Judgements/TauJudgement.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Scoring; 3 | 4 | namespace osu.Game.Rulesets.Tau.Judgements 5 | { 6 | public class TauJudgement : Judgement 7 | { 8 | public override HitResult MaxResult => HitResult.Great; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Judgements/TauJudgementResult.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Objects; 3 | 4 | namespace osu.Game.Rulesets.Tau.Judgements 5 | { 6 | public class TauJudgementResult : JudgementResult 7 | { 8 | public float? DeltaAngle; 9 | 10 | public TauJudgementResult(HitObject hitObject, Judgement judgement) 11 | : base(hitObject, judgement) 12 | { 13 | } 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Judgements/TauTickJudgement.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Scoring; 3 | 4 | namespace osu.Game.Rulesets.Tau.Judgements 5 | { 6 | public class TauTickJudgement : Judgement 7 | { 8 | public override HitResult MaxResult => HitResult.SmallTickHit; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/BeatmapStrings.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | 3 | namespace osu.Game.Rulesets.Tau.Localisation 4 | { 5 | public class BeatmapStrings 6 | { 7 | private const string prefix = @"osu.Game.Rulesets.Tau.Localisation.Translations.Beatmap"; 8 | 9 | /// 10 | /// "Beat count" 11 | /// 12 | public static LocalisableString BeatCount => new TranslatableString(getKey(@"beat_count"), @"Beat count"); 13 | 14 | /// 15 | /// "Slider count" 16 | /// 17 | public static LocalisableString SliderCount => new TranslatableString(getKey(@"slider_count"), @"Slider count"); 18 | 19 | /// 20 | /// "Hard Beat count" 21 | /// 22 | public static LocalisableString HardBeatCount => new TranslatableString(getKey(@"hard_beat_count"), @"Hard Beat count"); 23 | 24 | private static string getKey(string key) => $@"{prefix}:{key}"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/InputStrings.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | 3 | namespace osu.Game.Rulesets.Tau.Localisation 4 | { 5 | public class InputStrings 6 | { 7 | private const string prefix = @"osu.Game.Rulesets.Tau.Localisation.Translations.Inputs"; 8 | 9 | /// 10 | /// "Left Button" 11 | /// 12 | public static LocalisableString LeftButton => new TranslatableString(getKey(@"left_button"), @"Left Button"); 13 | 14 | /// 15 | /// "Right Button" 16 | /// 17 | public static LocalisableString RightButton => new TranslatableString(getKey(@"right_button"), @"Right Button"); 18 | 19 | /// 20 | /// "Hard Button 1" 21 | /// 22 | public static LocalisableString HardButton1 => new TranslatableString(getKey(@"hard_button_1"), @"Hard Button 1"); 23 | 24 | /// 25 | /// "Hard Button 2" 26 | /// 27 | public static LocalisableString HardButton2 => new TranslatableString(getKey(@"hard_button_2"), @"Hard Button 2"); 28 | 29 | private static string getKey(string key) => $@"{prefix}:{key}"; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/KiaiTypeStrings.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | 3 | namespace osu.Game.Rulesets.Tau.Localisation 4 | { 5 | public static class KiaiTypeStrings 6 | { 7 | private const string prefix = @"osu.Game.Rulesets.Tau.Localisation.Translations.KiaiType"; 8 | 9 | /// 10 | /// "Turbulence" 11 | /// 12 | public static LocalisableString Turbulence => new TranslatableString(getKey(@"turbulence"), @"Turbulence"); 13 | 14 | /// 15 | /// "Classic" 16 | /// 17 | public static LocalisableString Classic => new TranslatableString(getKey(@"classic"), @"Classic"); 18 | 19 | /// 20 | /// "None" 21 | /// 22 | public static LocalisableString None => new TranslatableString(getKey(@"none"), @"None"); 23 | 24 | private static string getKey(string key) => $@"{prefix}:{key}"; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/SettingStrings.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | 3 | namespace osu.Game.Rulesets.Tau.Localisation 4 | { 5 | public static class SettingStrings 6 | { 7 | private const string prefix = @"osu.Game.Rulesets.Tau.Localisation.Translations.Settings"; 8 | 9 | /// 10 | /// "Show Effects" 11 | /// 12 | public static LocalisableString ShowEffects => new TranslatableString(getKey(@"show_effects"), @"Show Effects"); 13 | 14 | /// 15 | /// "Show Slider Effects" 16 | /// 17 | public static LocalisableString ShowSliderEffects => new TranslatableString(getKey(@"show_slider_effects"), @"Show Slider Effects"); 18 | 19 | /// 20 | /// "Show Visualizer" 21 | /// 22 | public static LocalisableString ShowVisualizer => new TranslatableString(getKey(@"show_visualizer"), @"Show Visualizer"); 23 | 24 | /// 25 | /// "Hit Lighting" 26 | /// 27 | public static LocalisableString HitLighting => new TranslatableString(getKey(@"hit_lighting"), @"Hit Lighting"); 28 | 29 | /// 30 | /// "Kiai Type" 31 | /// 32 | public static LocalisableString KiaiType => new TranslatableString(getKey(@"kiai_type"), @"Kiai Type"); 33 | 34 | /// 35 | /// "Playfield Dim" 36 | /// 37 | public static LocalisableString PlayfieldDim => new TranslatableString(getKey(@"playfield_dim"), @"Playfield Dim"); 38 | 39 | /// 40 | /// "Notes Size" 41 | /// 42 | public static LocalisableString NotesSize => new TranslatableString(getKey(@"notes_size"), @"Notes Size"); 43 | 44 | private static string getKey(string key) => $@"{prefix}:{key}"; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.be.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.bg.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ca.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.cs.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.da.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.el.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.fa.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.fi.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.fil.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.he.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.hr.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.id.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ja.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ko.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 입자 흩날림 51 | 52 | 53 | 클래식 54 | 55 | 56 | 없음 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.lt.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.lv.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ms.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.nl.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.no.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.pt.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ro.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Turbulence 51 | 52 | 53 | Classic 54 | 55 | 56 | None 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.ru.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | Вихревой 51 | 52 | 53 | Классический 54 | 55 | 56 | Нет 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/Translations/KiaiType.zh-Hans.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 紊乱 51 | 52 | 53 | 传统的 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Localisation/UiStrings.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | 3 | namespace osu.Game.Rulesets.Tau.Localisation 4 | { 5 | public class UiStrings 6 | { 7 | private const string prefix = @"osu.Game.Rulesets.Tau.Localisation.Translations.UI"; 8 | 9 | /// 10 | /// "Ticks" 11 | /// 12 | public static LocalisableString Ticks => new TranslatableString(getKey(@"ticks"), @"Ticks"); 13 | 14 | /// 15 | /// "Timing Distribution" 16 | /// 17 | public static LocalisableString TimingDistribution => new TranslatableString(getKey(@"timing_distribution"), @"Timing Distribution"); 18 | 19 | /// 20 | /// "Paddle Distribution" 21 | /// 22 | public static LocalisableString PaddleDistribution => new TranslatableString(getKey(@"paddle_distribution"), @"Paddle Distribution"); 23 | 24 | /// 25 | /// "Sliders" 26 | /// 27 | public static LocalisableString Sliders => new TranslatableString(getKey(@"distribution_sliders"), @"Sliders"); 28 | 29 | /// 30 | /// "Beats" 31 | /// 32 | public static LocalisableString Beats => new TranslatableString(getKey(@"distribution_beats"), @"Beats"); 33 | 34 | /// 35 | /// "Move the cursor to the highlighted area." 36 | /// 37 | public static LocalisableString ResumeMessage => new TranslatableString(getKey(@"resume_overlay_message"), @"Move the cursor to the highlighted area."); 38 | 39 | private static string getKey(string key) => $@"{prefix}:{key}"; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModAutoplay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.Tau.Replays; 7 | 8 | namespace osu.Game.Rulesets.Tau.Mods 9 | { 10 | public class TauModAutoplay : ModAutoplay 11 | { 12 | public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(TauModAutopilot) }).ToArray(); 13 | 14 | public override ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) 15 | => new(new TauAutoGenerator(beatmap, mods).Generate(), new ModCreatedUser { Username = "Astraeus" }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModCinema.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.Tau.Objects; 7 | using osu.Game.Rulesets.Tau.Replays; 8 | 9 | namespace osu.Game.Rulesets.Tau.Mods 10 | { 11 | public class TauModCinema : ModCinema 12 | { 13 | public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(TauModAutopilot) }).ToArray(); 14 | 15 | public override ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) 16 | => new(new TauAutoGenerator(beatmap, mods).Generate(), new ModCreatedUser { Username = "Astraeus" }); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModDaycore.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.Tau.Mods 4 | { 5 | public class TauModDaycore : ModDaycore 6 | { 7 | public override double ScoreMultiplier => 0.3; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModDifficultyAdjust.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Configuration; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.Tau.Localisation; 7 | 8 | namespace osu.Game.Rulesets.Tau.Mods 9 | { 10 | public class TauModDifficultyAdjust : ModDifficultyAdjust 11 | { 12 | [SettingSource(typeof(ModStrings), nameof(ModStrings.DifficultyAdjustPaddleSizeName), nameof(ModStrings.DifficultyAdjustPaddleSizeDescription), 13 | FIRST_SETTING_ORDER - 1, SettingControlType = typeof(DifficultyAdjustSettingsControl))] 14 | public DifficultyBindable PaddleSize { get; } = new DifficultyBindable 15 | { 16 | Precision = 0.1f, 17 | MinValue = 0, 18 | MaxValue = 10, 19 | ExtendedMaxValue = 11, 20 | ReadCurrentFromDifficulty = diff => diff.CircleSize, 21 | }; 22 | 23 | // [SettingSource("Approach Rate", "Override a beatmap's set AR.", LAST_SETTING_ORDER + 1, SettingControlType = typeof(DifficultyAdjustSettingsControl))] 24 | [SettingSource(typeof(ModStrings), nameof(ModStrings.DifficultyAdjustApproachRateName), nameof(ModStrings.DifficultyAdjustApproachRateDescription), 25 | FIRST_SETTING_ORDER + 1, SettingControlType = typeof(DifficultyAdjustSettingsControl))] 26 | public DifficultyBindable ApproachRate { get; } = new DifficultyBindable 27 | { 28 | Precision = 0.1f, 29 | MinValue = 0, 30 | MaxValue = 10, 31 | ExtendedMaxValue = 11, 32 | ReadCurrentFromDifficulty = diff => diff.ApproachRate, 33 | }; 34 | 35 | public override IEnumerable<(LocalisableString setting, LocalisableString value)> SettingDescription 36 | { 37 | get 38 | { 39 | if (!PaddleSize.IsDefault) 40 | yield return (ModStrings.DifficultyAdjustPaddleSizeName, $"{PaddleSize.Value:N1}"); 41 | 42 | foreach (var setting in base.SettingDescription) 43 | yield return setting; 44 | 45 | if (!ApproachRate.IsDefault) 46 | yield return (ModStrings.DifficultyAdjustApproachRateName, $"{ApproachRate.Value:N1}"); 47 | } 48 | } 49 | 50 | protected override void ApplySettings(BeatmapDifficulty difficulty) 51 | { 52 | base.ApplySettings(difficulty); 53 | 54 | if (PaddleSize.Value != null) difficulty.CircleSize = PaddleSize.Value.Value; 55 | if (ApproachRate.Value != null) difficulty.ApproachRate = ApproachRate.Value.Value; 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModDoubleTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.Tau.Mods 4 | { 5 | public class TauModDoubleTime : ModDoubleTime 6 | { 7 | public override double ScoreMultiplier => 1.12; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModDual.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Configuration; 4 | using osu.Game.Rulesets.Mods; 5 | using osu.Game.Rulesets.Tau.Localisation; 6 | 7 | namespace osu.Game.Rulesets.Tau.Mods 8 | { 9 | public class TauModDual : Mod 10 | { 11 | public override string Name => "Dual"; 12 | public override string Acronym => "DL"; 13 | public override LocalisableString Description => ModStrings.DualDescription; 14 | public override double ScoreMultiplier => 1; 15 | public override ModType Type => ModType.Fun; 16 | 17 | public override bool HasImplementation => true; 18 | 19 | [SettingSource(typeof(ModStrings), nameof(ModStrings.DualPaddleCountName))] 20 | public BindableNumber PaddleCount { get; } = new() 21 | { 22 | Value = 2, 23 | Default = 2, 24 | MinValue = 2, 25 | MaxValue = 4 26 | }; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModEasy.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | using osu.Game.Rulesets.Mods; 3 | using osu.Game.Rulesets.Tau.Localisation; 4 | 5 | namespace osu.Game.Rulesets.Tau.Mods 6 | { 7 | public class TauModEasy : ModEasyWithExtraLives 8 | { 9 | public override LocalisableString Description => ModStrings.EasyDescription; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModFadeIn.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics.Sprites; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Rulesets.Tau.Localisation; 4 | 5 | namespace osu.Game.Rulesets.Tau.Mods 6 | { 7 | public class TauModFadeIn : TauModHidden 8 | { 9 | public override IconUsage? Icon => TauIcons.ModFadeIn; 10 | 11 | public override string Acronym => "FI"; 12 | 13 | // Modification from osu!mania's description of Hidden mod. 14 | public override LocalisableString Description => ModStrings.FadeInDescription; 15 | protected override MaskingMode Mode => MaskingMode.FadeIn; 16 | protected override float InitialCoverage => 0.25f; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModFadeOut.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics.Sprites; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Rulesets.Tau.Localisation; 4 | 5 | namespace osu.Game.Rulesets.Tau.Mods 6 | { 7 | public class TauModFadeOut : TauModHidden 8 | { 9 | public override IconUsage? Icon => TauIcons.ModFadeOut; 10 | public override string Acronym => "FO"; 11 | 12 | // Modification from osu!mania's description of Hidden mod. 13 | public override LocalisableString Description => ModStrings.FadeOutDescription; 14 | protected override MaskingMode Mode => MaskingMode.FadeOut; 15 | protected override float InitialCoverage => 0.4f; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModHalfTime.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.Tau.Mods 4 | { 5 | public class TauModHalfTime : ModHalfTime 6 | { 7 | public override double ScoreMultiplier => 0.3; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModHardRock.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Objects; 3 | using osu.Game.Rulesets.Tau.Objects; 4 | 5 | namespace osu.Game.Rulesets.Tau.Mods 6 | { 7 | public class TauModHardRock : ModHardRock, IApplicableToHitObject 8 | { 9 | public override double ScoreMultiplier => 1.06; 10 | 11 | public void ApplyToHitObject(HitObject hitObject) 12 | { 13 | if (hitObject is not IHasAngle angledHitObject) 14 | return; 15 | 16 | var newAngle = angledHitObject.Angle; 17 | newAngle -= 180; 18 | newAngle.NormalizeAngle(); 19 | 20 | angledHitObject.Angle = newAngle; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModImpossibleSliders.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | using osu.Game.Beatmaps; 3 | using osu.Game.Rulesets.Mods; 4 | using osu.Game.Rulesets.Tau.Beatmaps; 5 | using osu.Game.Rulesets.Tau.Localisation; 6 | 7 | namespace osu.Game.Rulesets.Tau.Mods 8 | { 9 | public class TauModImpossibleSliders : Mod, IApplicableToBeatmapConverter 10 | { 11 | public override string Name => "Impossible Sliders"; 12 | public override LocalisableString Description => ModStrings.ImpossibleSlidersDescription; 13 | public override double ScoreMultiplier => 1f; 14 | public override string Acronym => "IS"; 15 | 16 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 17 | { 18 | var converter = (TauBeatmapConverter)beatmapConverter; 19 | 20 | converter.CanConvertImpossibleSliders = true; 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModInverse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using osu.Framework.Graphics.Sprites; 4 | using osu.Framework.Localisation; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.Objects; 7 | using osu.Game.Rulesets.Tau.Localisation; 8 | using osu.Game.Rulesets.Tau.Objects; 9 | using osu.Game.Rulesets.Tau.UI; 10 | using osu.Game.Rulesets.UI; 11 | using osuTK; 12 | 13 | namespace osu.Game.Rulesets.Tau.Mods 14 | { 15 | public class TauModInverse : Mod, IApplicableToHitObject, IApplicableToDrawableRuleset 16 | { 17 | public override string Name => "Inverse"; 18 | public override string Acronym => "IN"; 19 | public override ModType Type => ModType.Fun; 20 | public override IconUsage? Icon => TauIcons.ModInverse; 21 | public override LocalisableString Description => ModStrings.InverseDescription; 22 | public override double ScoreMultiplier => 1; 23 | public override Type[] IncompatibleMods => new[] { typeof(TauModHidden) }; 24 | 25 | private const float preempt_scale = 2; 26 | 27 | public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) 28 | { 29 | var ruleset = (TauDrawableRuleset)drawableRuleset; 30 | var properties = ruleset.CachedProperties; 31 | 32 | properties.InverseModEnabled.Value = true; 33 | 34 | var playfield = ruleset.Playfield; 35 | playfield.Scale = new Vector2(0.5f); 36 | } 37 | 38 | public void ApplyToHitObject(HitObject hitObject) 39 | { 40 | var tauHitObject = (TauHitObject)hitObject; 41 | tauHitObject.TimePreempt *= preempt_scale; 42 | 43 | foreach (var nestedHitObject in tauHitObject.NestedHitObjects.Cast()) 44 | { 45 | nestedHitObject.TimePreempt *= preempt_scale; 46 | } 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModLite.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Graphics.Sprites; 4 | using osu.Framework.Localisation; 5 | using osu.Game.Beatmaps; 6 | using osu.Game.Configuration; 7 | using osu.Game.Rulesets.Mods; 8 | using osu.Game.Rulesets.Tau.Beatmaps; 9 | using osu.Game.Rulesets.Tau.Localisation; 10 | 11 | namespace osu.Game.Rulesets.Tau.Mods 12 | { 13 | public class TauModLite : Mod, IApplicableToBeatmapConverter 14 | { 15 | public override string Name => "Lite"; 16 | public override string Acronym => "LT"; 17 | public override double ScoreMultiplier => 1.0; 18 | public override IconUsage? Icon => FontAwesome.Solid.History; 19 | public override LocalisableString Description => ModStrings.LiteDescription; 20 | public override ModType Type => ModType.Conversion; 21 | 22 | public override Type[] IncompatibleMods => new[] { typeof(TauModStrict), typeof(TauModLenience) }; 23 | 24 | [SettingSource(typeof(ModStrings), nameof(ModStrings.LiteToggleSlidersName), nameof(ModStrings.LiteToggleSlidersDescription))] 25 | public Bindable ToggleSliders { get; } = new Bindable(false); 26 | 27 | [SettingSource(typeof(ModStrings), nameof(ModStrings.LiteToggleHardBeatsName), nameof(ModStrings.LiteToggleHardBeatsDescription))] 28 | public Bindable ToggleHardBeats { get; } = new Bindable(false); 29 | 30 | // maybe replace this with `BeatDivisorControl`? 31 | [SettingSource(typeof(ModStrings), nameof(ModStrings.LiteSliderDivisionLevelName), nameof(ModStrings.LiteSliderDivisionLevelDescription))] 32 | public BindableInt SlidersDivisionLevel { get; } = new BindableInt 33 | { 34 | Value = 2, 35 | Default = 2, 36 | MinValue = 1, 37 | MaxValue = 64 38 | }; 39 | 40 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 41 | { 42 | var converter = (TauBeatmapConverter)beatmapConverter; 43 | 44 | converter.CanConvertToHardBeats = ToggleHardBeats.Value; 45 | converter.CanConvertToSliders = ToggleSliders.Value; 46 | converter.SliderDivisor = SlidersDivisionLevel.Value; 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModNightcore.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | using osu.Game.Rulesets.Tau.Objects; 3 | 4 | namespace osu.Game.Rulesets.Tau.Mods 5 | { 6 | public class TauModNightcore : ModNightcore 7 | { 8 | public override double ScoreMultiplier => 1.12; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModNoFail.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.Tau.Mods 4 | { 5 | public class TauModNoFail : ModNoFail 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModNoScope.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Utils; 3 | using osu.Game.Configuration; 4 | using osu.Game.Overlays.Settings; 5 | using osu.Game.Rulesets.Mods; 6 | using osu.Game.Rulesets.UI; 7 | using System; 8 | using osu.Framework.Localisation; 9 | using osu.Game.Rulesets.Tau.Localisation; 10 | 11 | namespace osu.Game.Rulesets.Tau.Mods 12 | { 13 | public class TauModNoScope : ModNoScope, IUpdatableByPlayfield 14 | { 15 | public override LocalisableString Description => ModStrings.NoScopeDescription; 16 | 17 | [SettingSource( 18 | typeof(ModStrings), 19 | nameof(ModStrings.NoScopeThresholdName), 20 | nameof(ModStrings.NoScopeThresholdDescription), 21 | SettingControlType = typeof(SettingsSlider) 22 | )] 23 | public override BindableInt HiddenComboCount { get; } = new() 24 | { 25 | Default = 10, 26 | Value = 10, 27 | MinValue = 0, 28 | MaxValue = 50, 29 | }; 30 | 31 | public void Update(Playfield playfield) 32 | { 33 | bool shouldAlwaysShowCursor = IsBreakTime.Value; 34 | float targetAlpha = shouldAlwaysShowCursor ? 1 : ComboBasedAlpha; 35 | playfield.Cursor.Alpha = (float)Interpolation.Lerp(playfield.Cursor.Alpha, targetAlpha, Math.Clamp(playfield.Time.Elapsed / TRANSITION_DURATION, 0, 1)); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModPerfect.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Mods; 2 | 3 | namespace osu.Game.Rulesets.Tau.Mods 4 | { 5 | public class TauModPerfect : ModPerfect 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModRoundabout.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Graphics.Sprites; 4 | using osu.Game.Beatmaps; 5 | using osu.Game.Configuration; 6 | using osu.Game.Rulesets.Mods; 7 | using osu.Game.Rulesets.Tau.Beatmaps; 8 | using System; 9 | using osu.Framework.Localisation; 10 | using osu.Game.Rulesets.Tau.Localisation; 11 | using System.Collections.Generic; 12 | 13 | namespace osu.Game.Rulesets.Tau.Mods 14 | { 15 | public class TauModRoundabout : Mod, IApplicableToBeatmapConverter 16 | { 17 | public override string Name => "Roundabout"; 18 | public override string Acronym => "RB"; 19 | public override LocalisableString Description => ModStrings.RoundaboutDescription; 20 | public override double ScoreMultiplier => 1; 21 | public override ModType Type => ModType.Fun; 22 | public override bool UserPlayable => true; 23 | public override IconUsage? Icon => FontAwesome.Solid.Redo; 24 | public override bool HasImplementation => true; 25 | 26 | [SettingSource(typeof(ModStrings), nameof(ModStrings.RoundaboutDirectionName))] 27 | public Bindable Direction { get; } = new(); 28 | 29 | public override IEnumerable<(LocalisableString setting, LocalisableString value)> SettingDescription 30 | { 31 | get 32 | { 33 | yield return (ModStrings.RoundaboutDirectionName, $"{Direction.Value:N1}"); 34 | } 35 | } 36 | 37 | public override void ResetSettingsToDefaults() 38 | { 39 | Direction.SetDefault(); 40 | base.ResetSettingsToDefaults(); 41 | } 42 | 43 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 44 | { 45 | ((TauBeatmapConverter)beatmapConverter).LockedDirection = Direction.Value; 46 | } 47 | 48 | public override Type[] IncompatibleMods => new[] { typeof(TauModAutoplay) }; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModShowoffAutoplay.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using osu.Framework.Graphics.Sprites; 5 | using osu.Game.Beatmaps; 6 | using osu.Game.Rulesets.Mods; 7 | using osu.Game.Rulesets.Tau.Replays; 8 | 9 | namespace osu.Game.Rulesets.Tau.Mods 10 | { 11 | public class TauModShowoffAutoplay : ModAutoplay 12 | { 13 | public override IconUsage? Icon => FontAwesome.Regular.Eye; 14 | public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(TauModAutopilot) }).ToArray(); 15 | public override bool HasImplementation => false; 16 | 17 | public override ModReplayData CreateReplayData(IBeatmap beatmap, IReadOnlyList mods) 18 | => new(new ShowoffAutoGenerator(beatmap, mods).Generate(), new ModCreatedUser { Username = "Redez" }); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModStrict.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework.Localisation; 3 | using osu.Game.Beatmaps; 4 | using osu.Game.Rulesets.Mods; 5 | using osu.Game.Rulesets.Tau.Beatmaps; 6 | using osu.Game.Rulesets.Tau.Localisation; 7 | 8 | namespace osu.Game.Rulesets.Tau.Mods 9 | { 10 | public class TauModStrict : Mod, IApplicableToBeatmapConverter 11 | { 12 | public override string Name => "Strict"; 13 | public override LocalisableString Description => ModStrings.StrictDescription; 14 | public override double ScoreMultiplier => 1.2; 15 | public override string Acronym => "ST"; 16 | public override ModType Type => ModType.DifficultyIncrease; 17 | public override Type[] IncompatibleMods => new[] { typeof(TauModLenience), typeof(TauModLite) }; 18 | 19 | public void ApplyToBeatmapConverter(IBeatmapConverter beatmapConverter) 20 | { 21 | var converter = (TauBeatmapConverter)beatmapConverter; 22 | converter.HardBeatsAreStrict = true; 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModSuddenDeath.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using osu.Game.Rulesets.Mods; 4 | 5 | namespace osu.Game.Rulesets.Tau.Mods 6 | { 7 | public class TauModSuddenDeath : ModSuddenDeath 8 | { 9 | public override Type[] IncompatibleMods => base.IncompatibleMods.Concat(new[] { typeof(TauModAutopilot) }).ToArray(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Mods/TauModTraceable.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Localisation; 2 | using osu.Game.Rulesets.Mods; 3 | using osu.Game.Rulesets.Tau.Localisation; 4 | using osu.Game.Rulesets.Tau.Objects; 5 | using osu.Game.Rulesets.Tau.UI; 6 | using osu.Game.Rulesets.UI; 7 | 8 | namespace osu.Game.Rulesets.Tau.Mods 9 | { 10 | public class TauModTraceable : Mod, IApplicableToDrawableRuleset 11 | { 12 | public override string Name => "Traceable"; 13 | public override string Acronym => "TC"; 14 | public override ModType Type => ModType.Fun; 15 | public override LocalisableString Description => ModStrings.TraceableDescription; 16 | public override double ScoreMultiplier => 1; 17 | 18 | public void ApplyToDrawableRuleset(DrawableRuleset drawableRuleset) 19 | { 20 | if ((drawableRuleset as TauDrawableRuleset)?.Playfield is TauPlayfield playfield) 21 | playfield.PlayfieldPiece.Alpha = 0; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/AngledTauHitObject.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | 3 | namespace osu.Game.Rulesets.Tau.Objects 4 | { 5 | /// 6 | /// A that has an angle parameter. 7 | /// 8 | public class AngledTauHitObject : TauHitObject, IHasAngle 9 | { 10 | public BindableFloat AngleBindable = new(); 11 | 12 | public float Angle 13 | { 14 | get => AngleBindable.Value; 15 | set => AngleBindable.Value = value; 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Beat.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public class Beat : AngledTauHitObject 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/DrawableSliderHardBeat.cs: -------------------------------------------------------------------------------- 1 | using osuTK; 2 | 3 | namespace osu.Game.Rulesets.Tau.Objects.Drawables 4 | { 5 | public partial class DrawableSliderHardBeat : DrawableStrictHardBeat 6 | { 7 | public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; 8 | 9 | public DrawableSliderHardBeat() 10 | { 11 | } 12 | 13 | public DrawableSliderHardBeat(SliderHardBeat hitObject) 14 | : base(hitObject) 15 | { 16 | Scale = new Vector2(1.025f); 17 | } 18 | 19 | protected override float GetSliderOffset() => DrawableSlider.HitObject.Angle; 20 | 21 | public float GetAbsoluteAngle() => HitObject.Angle + GetCurrentOffset(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/DrawableSliderHead.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects.Drawables 2 | { 3 | public partial class DrawableSliderHead : DrawableBeat 4 | { 5 | public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; 6 | 7 | public DrawableSliderHead() 8 | { 9 | } 10 | 11 | public DrawableSliderHead(SliderHeadBeat hitObject) 12 | : base(hitObject) 13 | { 14 | } 15 | 16 | protected override float GetCurrentOffset() => DrawableSlider.HitObject.Angle; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/DrawableSliderTick.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Scoring; 2 | 3 | namespace osu.Game.Rulesets.Tau.Objects.Drawables 4 | { 5 | public partial class DrawableSliderTick : DrawableAngledTauHitObject 6 | { 7 | public DrawableSlider DrawableSlider => (DrawableSlider)ParentHitObject; 8 | 9 | public override bool DisplayResult => false; 10 | 11 | public DrawableSliderTick() 12 | : this(null) 13 | { 14 | } 15 | 16 | public DrawableSliderTick(SliderTick hitObject) 17 | : base(hitObject) 18 | { 19 | } 20 | 21 | protected override void CheckForResult(bool userTriggered, double timeOffset) 22 | { 23 | if (HitObject.StartTime <= Time.Current) 24 | ApplyResult(DrawableSlider.Tracking.Value ? HitResult.SmallTickHit : HitResult.SmallTickMiss); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/ICanApplyResult.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Objects.Drawables; 2 | using osu.Game.Rulesets.Scoring; 3 | 4 | namespace osu.Game.Rulesets.Tau.Objects.Drawables 5 | { 6 | public interface ICanApplyResult 7 | { 8 | /// 9 | /// Forces a result to the . 10 | /// 11 | /// The adjustment to be made to the result. 12 | public void ForcefullyApplyResult(HitResult result); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/Pieces/BeatPiece.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Shapes; 3 | 4 | namespace osu.Game.Rulesets.Tau.Objects.Drawables.Pieces 5 | { 6 | public partial class BeatPiece : Box 7 | { 8 | public BeatPiece() 9 | { 10 | RelativeSizeAxes = Axes.Both; 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/Pieces/HardBeatPiece.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Graphics.Containers; 4 | using osu.Framework.Graphics.Shapes; 5 | using osu.Framework.Utils; 6 | using osuTK.Graphics; 7 | 8 | namespace osu.Game.Rulesets.Tau.Objects.Drawables.Pieces 9 | { 10 | public partial class HardBeatPiece : CircularContainer 11 | { 12 | public BindableFloat NoteSize = new(16f); 13 | 14 | public HardBeatPiece() 15 | { 16 | Masking = true; 17 | BorderThickness = 5; 18 | BorderColour = Color4.White; 19 | RelativeSizeAxes = Axes.Both; 20 | Anchor = Anchor.Centre; 21 | Origin = Anchor.Centre; 22 | FillAspectRatio = 1; 23 | FillMode = FillMode.Fit; 24 | 25 | Child = new Box 26 | { 27 | RelativeSizeAxes = Axes.Both, 28 | Alpha = 0, 29 | AlwaysPresent = true 30 | }; 31 | 32 | NoteSize.BindValueChanged(value => BorderThickness = convertNoteSizeToThickness(value.NewValue)); 33 | } 34 | 35 | private float convertNoteSizeToThickness(float noteSize) 36 | => Interpolation.ValueAt(noteSize, 3f, 15f, 10f, 25f); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/Pieces/SkinnableLighting.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Objects.Drawables; 3 | using osu.Game.Skinning; 4 | using osuTK.Graphics; 5 | 6 | namespace osu.Game.Rulesets.Tau.Objects.Drawables.Pieces 7 | { 8 | public partial class SkinnableLighting : SkinnableSprite 9 | { 10 | private DrawableTauJudgement targetJudgement; 11 | private JudgementResult targetResult; 12 | 13 | public SkinnableLighting() 14 | : base("lighting") 15 | { 16 | } 17 | 18 | protected override void SkinChanged(ISkinSource skin) 19 | { 20 | base.SkinChanged(skin); 21 | updateColour(); 22 | } 23 | 24 | /// 25 | /// Updates the lighting colour from a given hitobject and result. 26 | /// 27 | /// The that's been judged. 28 | /// The that was judged with. 29 | public void SetColourFrom(DrawableTauJudgement targetJudgement, JudgementResult targetResult) 30 | { 31 | this.targetJudgement = targetJudgement; 32 | this.targetResult = targetResult; 33 | 34 | updateColour(); 35 | } 36 | 37 | private void updateColour() 38 | { 39 | if (targetJudgement == null || targetResult == null) 40 | Colour = Color4.White; 41 | else 42 | Colour = targetResult.IsHit ? targetJudgement.AccentColour : Color4.Transparent; 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/Drawables/Pieces/StrictHardBeatPiece.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Graphics; 4 | using osu.Framework.Graphics.UserInterface; 5 | using osu.Framework.Utils; 6 | using osuTK; 7 | using osuTK.Graphics; 8 | 9 | namespace osu.Game.Rulesets.Tau.Objects.Drawables.Pieces 10 | { 11 | public partial class StrictHardBeatPiece : CircularProgress 12 | { 13 | public BindableFloat NoteSize = new(16f); 14 | public BindableDouble AngleRange = new(25 * 0.75); 15 | 16 | public StrictHardBeatPiece() 17 | { 18 | Colour = Color4.White; 19 | RelativeSizeAxes = Axes.Both; 20 | Anchor = Anchor.Centre; 21 | Origin = Anchor.Centre; 22 | FillAspectRatio = 1; 23 | FillMode = FillMode.Fit; 24 | InnerRadius = 1f; 25 | 26 | AngleRange.BindValueChanged(val => 27 | { 28 | Progress = val.NewValue / 360; 29 | Rotation = -(float)(val.NewValue / 2); 30 | }, true); 31 | } 32 | 33 | [BackgroundDependencyLoader] 34 | private void load() 35 | { 36 | // Size is set to zero here as to avoid standard fallback to original sprite's size (1,1), 37 | // see: https://github.com/ppy/osu-framework/blob/603e15fb2e68826e55878dfc09e1d7414b7cdf90/osu.Framework/Graphics/Sprites/Sprite.cs#L181-L182 38 | Size = Vector2.Zero; 39 | } 40 | 41 | private float toNormalized(float value) 42 | => value / DrawWidth; 43 | 44 | private float convertNoteSizeToThickness(float noteSize) 45 | => Interpolation.ValueAt(noteSize, toNormalized(20f), toNormalized(50f), 10f, 25f); 46 | 47 | protected override void Update() 48 | { 49 | base.Update(); 50 | 51 | if (!IsLoaded || NoteSize.Value == 0 || DrawWidth == 0) 52 | return; 53 | 54 | InnerRadius = convertNoteSizeToThickness(NoteSize.Value); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/HardBeat.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public class HardBeat : TauHitObject 4 | { 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/IHasAngle.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public interface IHasAngle 4 | { 5 | public float Angle { get; set; } 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/IHasOffsetAngle.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public interface IHasOffsetAngle : IHasAngle 4 | { 5 | public float GetOffsetAngle(); 6 | 7 | public float GetAbsoluteAngle() => (Angle + GetOffsetAngle()).Normalize(); 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/SliderHardBeat.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public class SliderHardBeat : StrictHardBeat, IHasOffsetAngle 4 | { 5 | public Slider ParentSlider { get; set; } 6 | 7 | public float GetOffsetAngle() => ParentSlider.Angle; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/SliderHeadBeat.cs: -------------------------------------------------------------------------------- 1 | namespace osu.Game.Rulesets.Tau.Objects 2 | { 3 | public class SliderHeadBeat : Beat, IHasOffsetAngle 4 | { 5 | public Slider ParentSlider { get; set; } 6 | 7 | public float GetOffsetAngle() => ParentSlider.Angle; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/SliderRepeat.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Scoring; 2 | 3 | namespace osu.Game.Rulesets.Tau.Objects 4 | { 5 | public class SliderRepeat : AngledTauHitObject, IHasOffsetAngle 6 | { 7 | public int RepeatIndex { get; set; } 8 | 9 | public Slider ParentSlider { get; set; } 10 | 11 | public float GetOffsetAngle() => ParentSlider.Angle; 12 | 13 | protected override HitWindows CreateHitWindows() => HitWindows.Empty; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/SliderTick.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Scoring; 3 | using osu.Game.Rulesets.Tau.Judgements; 4 | 5 | namespace osu.Game.Rulesets.Tau.Objects 6 | { 7 | public class SliderTick : AngledTauHitObject, IHasOffsetAngle 8 | { 9 | public Slider ParentSlider { get; set; } 10 | 11 | public float GetOffsetAngle() => ParentSlider.Angle; 12 | 13 | public override Judgement CreateJudgement() => new TauTickJudgement(); 14 | 15 | protected override HitWindows CreateHitWindows() => HitWindows.Empty; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/StrictHardBeat.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Beatmaps; 2 | using osu.Game.Beatmaps.ControlPoints; 3 | using osu.Game.Rulesets.Tau.UI; 4 | 5 | namespace osu.Game.Rulesets.Tau.Objects 6 | { 7 | public class StrictHardBeat : AngledTauHitObject 8 | { 9 | public double Range { get; private set; } 10 | 11 | protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty) 12 | { 13 | base.ApplyDefaultsToSelf(controlPointInfo, difficulty); 14 | 15 | // TODO: maybe this should be a static method instead? 16 | var properties = new TauCachedProperties(); 17 | properties.SetRange(difficulty.CircleSize); 18 | 19 | double multiplier = IBeatmapDifficultyInfo.DifficultyRange(difficulty.OverallDifficulty, 0.1, 0.25, 0.5); 20 | 21 | Range = properties.AngleRange.Value * multiplier; 22 | } 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Objects/TauHitObject.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Game.Beatmaps; 3 | using osu.Game.Beatmaps.ControlPoints; 4 | using osu.Game.Rulesets.Judgements; 5 | using osu.Game.Rulesets.Objects; 6 | using osu.Game.Rulesets.Objects.Types; 7 | using osu.Game.Rulesets.Scoring; 8 | using osu.Game.Rulesets.Tau.Judgements; 9 | using osu.Game.Rulesets.Tau.Scoring; 10 | 11 | namespace osu.Game.Rulesets.Tau.Objects 12 | { 13 | public class TauHitObject : HitObject, IHasComboInformation 14 | { 15 | public double TimePreempt = 600; 16 | public double TimeFadeIn = 100; 17 | 18 | protected override HitWindows CreateHitWindows() => new TauHitWindow(); 19 | public override Judgement CreateJudgement() => new TauJudgement(); 20 | 21 | protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, IBeatmapDifficultyInfo difficulty) 22 | { 23 | base.ApplyDefaultsToSelf(controlPointInfo, difficulty); 24 | 25 | TimePreempt = IBeatmapDifficultyInfo.DifficultyRange(difficulty.ApproachRate, 1800, 1200, 450); 26 | } 27 | 28 | public virtual bool NewCombo { get; set; } 29 | 30 | public readonly Bindable ComboOffsetBindable = new Bindable(); 31 | 32 | public int ComboOffset 33 | { 34 | get => ComboOffsetBindable.Value; 35 | set => ComboOffsetBindable.Value = value; 36 | } 37 | 38 | public Bindable IndexInCurrentComboBindable { get; } = new Bindable(); 39 | 40 | public virtual int IndexInCurrentCombo 41 | { 42 | get => IndexInCurrentComboBindable.Value; 43 | set => IndexInCurrentComboBindable.Value = value; 44 | } 45 | 46 | public Bindable ComboIndexBindable { get; } = new Bindable(); 47 | 48 | public virtual int ComboIndex 49 | { 50 | get => ComboIndexBindable.Value; 51 | set => ComboIndexBindable.Value = value; 52 | } 53 | 54 | public Bindable ComboIndexWithOffsetsBindable { get; } = new Bindable(); 55 | 56 | public int ComboIndexWithOffsets 57 | { 58 | get => ComboIndexWithOffsetsBindable.Value; 59 | set => ComboIndexWithOffsetsBindable.Value = value; 60 | } 61 | 62 | public Bindable LastInComboBindable { get; } = new Bindable(); 63 | 64 | public bool LastInCombo 65 | { 66 | get => LastInComboBindable.Value; 67 | set => LastInComboBindable.Value = value; 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Replays/TauFramedReplayInputHandler.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using System.Linq; 3 | using osu.Framework.Input.StateChanges; 4 | using osu.Framework.Utils; 5 | using osu.Game.Replays; 6 | using osu.Game.Rulesets.Replays; 7 | 8 | namespace osu.Game.Rulesets.Tau.Replays 9 | { 10 | public class TauFramedReplayInputHandler : FramedReplayInputHandler 11 | { 12 | public TauFramedReplayInputHandler(Replay replay) 13 | : base(replay) 14 | { 15 | } 16 | 17 | protected override bool IsImportant(TauReplayFrame frame) => frame.Actions.Any(); 18 | 19 | protected override void CollectReplayInputs(List inputs) 20 | { 21 | var position = Interpolation.ValueAt(CurrentTime, StartFrame.Position, EndFrame.Position, StartFrame.Time, EndFrame.Time); 22 | 23 | inputs.Add(new MousePositionAbsoluteInput { Position = GamefieldToScreenSpace(position) }); 24 | inputs.Add(new ReplayState { PressedActions = CurrentFrame?.Actions ?? new List() }); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Replays/TauReplayFrame.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using osu.Game.Beatmaps; 3 | using osu.Game.Replays.Legacy; 4 | using osu.Game.Rulesets.Replays; 5 | using osu.Game.Rulesets.Replays.Types; 6 | using osuTK; 7 | 8 | namespace osu.Game.Rulesets.Tau.Replays 9 | { 10 | public class TauReplayFrame : ReplayFrame, IConvertibleReplayFrame 11 | { 12 | public List Actions = new(); 13 | public Vector2 Position; 14 | 15 | public TauReplayFrame() 16 | { 17 | } 18 | 19 | public TauReplayFrame(double time, Vector2 position, params TauAction[] actions) 20 | : base(time) 21 | { 22 | Position = position; 23 | Actions.AddRange(actions); 24 | } 25 | 26 | public void FromLegacy(LegacyReplayFrame currentFrame, IBeatmap beatmap, ReplayFrame lastFrame = null) 27 | { 28 | Position = currentFrame.Position; 29 | 30 | if (currentFrame.MouseLeft1) Actions.Add(TauAction.LeftButton); 31 | if (currentFrame.MouseRight1) Actions.Add(TauAction.RightButton); 32 | if (currentFrame.MouseLeft2) Actions.Add(TauAction.HardButton1); 33 | if (currentFrame.MouseRight2) Actions.Add(TauAction.HardButton2); 34 | } 35 | 36 | public LegacyReplayFrame ToLegacy(IBeatmap beatmap) 37 | { 38 | var state = ReplayButtonState.None; 39 | 40 | if (Actions.Contains(TauAction.LeftButton)) state |= ReplayButtonState.Left1; 41 | if (Actions.Contains(TauAction.RightButton)) state |= ReplayButtonState.Right1; 42 | if (Actions.Contains(TauAction.HardButton1)) state |= ReplayButtonState.Left2; 43 | if (Actions.Contains(TauAction.HardButton2)) state |= ReplayButtonState.Right2; 44 | 45 | return new LegacyReplayFrame(Time, Position.X, Position.Y, state); 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Fonts/tauFont.fnt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taulazer/tau/56fb5c992a1c316e28945a0f0be06dfcc6b72ea5/osu.Game.Rulesets.Tau/Resources/Fonts/tauFont.fnt -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Fonts/tauFont_0.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taulazer/tau/56fb5c992a1c316e28945a0f0be06dfcc6b72ea5/osu.Game.Rulesets.Tau/Resources/Fonts/tauFont_0.png -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_PlayfieldMask.fs: -------------------------------------------------------------------------------- 1 | layout(location = 0) in highp vec2 v_Position; 2 | layout(location = 1) in lowp vec4 v_Colour; 3 | 4 | layout(std140, set = 0, binding = 0) uniform m_maskParameters { 5 | highp vec2 aperturePos; 6 | highp vec2 apertureSize; 7 | }; 8 | 9 | layout(location = 0) out vec4 o_colour; 10 | 11 | const mediump float smoothness = 1.5; 12 | 13 | // highp precision is necessary for vertex positions to prevent catastrophic failure on GL_ES platforms 14 | lowp vec4 getColourAt(highp vec2 diff, highp vec2 size, lowp vec4 originalColour) 15 | { 16 | highp float dist = length(diff); 17 | highp float radius = length(size); 18 | 19 | return originalColour * vec4(1.0, 1.0, 1.0, smoothstep(radius, radius * smoothness, dist)); 20 | } 21 | 22 | void main(void) 23 | { 24 | o_colour = mix(getColourAt(aperturePos - v_Position, apertureSize, v_Colour), vec4(0, 0.0, 0, 1.0), 0.0); 25 | } 26 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_Slider.fs: -------------------------------------------------------------------------------- 1 | #include "sh_Utils.h" 2 | #include "sh_TextureWrapping.h" 3 | 4 | layout(location = 0) in highp vec2 v_Position; 5 | layout(location = 1) in lowp vec4 v_Colour; 6 | layout(location = 2) in highp vec2 v_TexCoord; 7 | layout(location = 3) in highp vec4 v_TexRect; 8 | layout(location = 4) in mediump vec2 v_BlendRange; 9 | layout(location = 5) in highp float v_Result; 10 | 11 | layout(std140, set = 0, binding = 0) uniform m_sliderParameters { 12 | highp vec2 centerPos; 13 | highp vec4 hitColor; 14 | highp float range; 15 | highp float fadeRange; 16 | bool reverse; 17 | }; 18 | 19 | layout(set = 1, binding = 0) uniform lowp texture2D m_texture; 20 | layout(set = 1, binding = 1) uniform lowp sampler m_sampler; 21 | 22 | layout(location = 0) out vec4 o_colour; 23 | 24 | void main(void) 25 | { 26 | vec4 colour = v_Colour * wrappedSampler(wrap(v_TexCoord, v_TexRect), v_TexRect, m_texture, m_sampler, -0.9); 27 | 28 | vec2 diff = v_Position - centerPos; 29 | float dist = sqrt(diff.x * diff.x + diff.y * diff.y); 30 | 31 | if ( reverse != dist <= range ) 32 | { 33 | o_colour = colour; 34 | } 35 | else 36 | { 37 | float progress = abs(dist - range) / fadeRange; 38 | o_colour = vec4(mix(vec3(1.0, 0.0, 0.0), vec3(hitColor.x, hitColor.y, hitColor.z), v_Result), mix(hitColor.w * colour.w, 0.0, progress)); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_SliderPositionAndColour.vs: -------------------------------------------------------------------------------- 1 | layout(location = 0) in highp vec2 m_Position; 2 | layout(location = 1) in lowp vec4 m_Colour; 3 | layout(location = 2) in highp vec2 m_TexCoord; 4 | layout(location = 3) in highp vec4 m_TexRect; 5 | layout(location = 4) in mediump vec2 m_BlendRange; 6 | layout(location = 5) in highp float m_Result; 7 | 8 | layout(location = 0) out vec2 v_Position; 9 | layout(location = 1) out vec4 v_Colour; 10 | layout(location = 2) out mediump vec2 v_TexCoord; 11 | layout(location = 3) out mediump vec4 v_TexRect; 12 | layout(location = 4) out mediump vec2 v_BlendRange; 13 | layout(location = 5) out float v_Result; 14 | 15 | void main(void) 16 | { 17 | gl_Position = g_ProjMatrix * vec4(m_Position.xy, 1.0, 1.0); 18 | 19 | v_Position = m_Position; 20 | v_Colour = m_Colour; 21 | v_Result = m_Result; 22 | v_TexCoord = m_TexCoord; 23 | v_TexRect = m_TexRect; 24 | v_BlendRange = m_BlendRange; 25 | 26 | gl_Position.z = 0.0; 27 | } -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_TriangularFlashlight.fs: -------------------------------------------------------------------------------- 1 | #define PI 3.14159265359 2 | #define TAU 6.28318530718 3 | 4 | layout(location = 0) in highp vec2 v_Position; 5 | layout(location = 1) in highp vec4 v_Colour; 6 | 7 | layout(std140, set = 0, binding = 0) uniform m_flashlightParameters { 8 | highp vec2 centerPos; 9 | highp float range; 10 | highp float rotation; 11 | lowp float flashlightDim; 12 | }; 13 | 14 | layout(location = 0) out vec4 o_colour; 15 | 16 | const mediump float smoothness = 24.0 / 180 * PI; 17 | 18 | float atan2(in mediump float y, in mediump float x) { 19 | return 2 * atan(y / (sqrt(x * x + y * y) + x)); 20 | } 21 | 22 | float angleDistance(mediump float a, mediump float b) { 23 | return mod(b - a + PI, TAU) - PI; 24 | } 25 | 26 | highp float theta = abs(angleDistance(atan2(v_Position.y - centerPos.y, v_Position.x - centerPos.x), rotation)); 27 | 28 | bool isInRange(mediump float radi, mediump float sigma) { 29 | float toCheck = (radi + sigma) / 2; 30 | return theta <= toCheck; 31 | } 32 | 33 | lowp vec4 getColourAt(lowp vec4 originalColour) 34 | { 35 | if (isInRange(range, 0.0)) { 36 | return vec4(0.0); 37 | } 38 | 39 | if (isInRange(range, smoothness)) { 40 | float angleDist = theta; 41 | angleDist -= range / 2; 42 | angleDist /= smoothness / 2; 43 | 44 | return originalColour * vec4(1.0, 1.0, 1.0, angleDist); 45 | } 46 | 47 | return originalColour * vec4(1.0); 48 | } 49 | 50 | void main(void) 51 | { 52 | o_colour = mix(getColourAt(v_Colour), vec4(0.0, 0.0, 0.0, 1.0), flashlightDim); 53 | } -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_VisualizerFade.fs: -------------------------------------------------------------------------------- 1 | #include "sh_Utils.h" 2 | #include "sh_Masking.h" 3 | #include "sh_TextureWrapping.h" 4 | 5 | layout(location = 5) in highp vec2 v_Position; 6 | layout(location = 2) in mediump vec2 v_TexCoord; 7 | 8 | layout(std140, set = 1, binding = 0) uniform m_visualizerParameters { 9 | highp vec2 centerPos; 10 | highp float range; 11 | highp float fadeRange; 12 | }; 13 | 14 | layout(set = 0, binding = 0) uniform lowp texture2D m_texture; 15 | layout(set = 0, binding = 1) uniform lowp sampler m_sampler; 16 | 17 | layout(location = 0) out vec4 o_colour; 18 | 19 | void main(void) 20 | { 21 | vec2 diff = v_Position - centerPos; 22 | float dist = sqrt(diff.x * diff.x + diff.y * diff.y); 23 | 24 | if ( dist <= range ) 25 | { 26 | discard; 27 | } 28 | else 29 | { 30 | vec2 wrappedCoord = wrap(v_TexCoord, v_TexRect); 31 | vec4 colour = getRoundedColor(wrappedSampler(wrappedCoord, v_TexRect, m_texture, m_sampler, -0.9), wrappedCoord); 32 | float progress = (fadeRange == 0.0) ? 1.0 : (abs(dist - range) / fadeRange); 33 | o_colour = vec4(colour.xyz, min(mix(0.0, colour.w, progress), colour.w)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Resources/Shaders/sh_VisualizerPositionAndColour.vs: -------------------------------------------------------------------------------- 1 | #include "sh_Utils.h" 2 | 3 | layout(location = 0) in highp vec2 m_Position; 4 | layout(location = 1) in lowp vec4 m_Colour; 5 | layout(location = 2) in mediump vec2 m_TexCoord; 6 | layout(location = 3) in mediump vec4 m_TexRect; 7 | layout(location = 4) in mediump vec2 m_BlendRange; 8 | 9 | layout(location = 0) out highp vec2 v_MaskingPosition; 10 | layout(location = 1) out lowp vec4 v_Colour; 11 | layout(location = 2) out mediump vec2 v_TexCoord; 12 | layout(location = 3) out mediump vec4 v_TexRect; 13 | layout(location = 4) out mediump vec2 v_BlendRange; 14 | layout(location = 5) out highp vec2 v_Position; 15 | 16 | void main(void) 17 | { 18 | // Transform from screen space to masking space. 19 | highp vec3 maskingPos = g_ToMaskingSpace * vec3(m_Position, 1.0); 20 | v_MaskingPosition = maskingPos.xy / maskingPos.z; 21 | 22 | v_Colour = m_Colour; 23 | v_TexCoord = m_TexCoord; 24 | v_TexRect = m_TexRect; 25 | v_BlendRange = m_BlendRange; 26 | v_Position = m_Position; 27 | 28 | gl_Position = g_ProjMatrix * vec4(m_Position, 1.0, 1.0); 29 | } -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Scoring/TauHitWindow.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Scoring; 2 | 3 | namespace osu.Game.Rulesets.Tau.Scoring 4 | { 5 | public class TauHitWindow : HitWindows 6 | { 7 | public override bool IsHitResultAllowed(HitResult result) 8 | => result switch 9 | { 10 | HitResult.Great 11 | or HitResult.Ok 12 | or HitResult.Miss 13 | or HitResult.SmallTickHit 14 | or HitResult.SmallTickMiss => true, 15 | _ => false 16 | }; 17 | 18 | protected override DifficultyRange[] GetRanges() => new[] 19 | { 20 | new DifficultyRange(HitResult.Great, 64, 49, 34), 21 | new DifficultyRange(HitResult.Ok, 127, 112, 97), 22 | new DifficultyRange(HitResult.Miss, 127, 112, 97), 23 | }; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/Scoring/TauScoreProcessor.cs: -------------------------------------------------------------------------------- 1 | using osu.Game.Rulesets.Judgements; 2 | using osu.Game.Rulesets.Objects; 3 | using osu.Game.Rulesets.Scoring; 4 | using osu.Game.Rulesets.Tau.Judgements; 5 | using osuTK; 6 | 7 | namespace osu.Game.Rulesets.Tau.Scoring 8 | { 9 | public partial class TauScoreProcessor : ScoreProcessor 10 | { 11 | public TauScoreProcessor(Ruleset ruleset) 12 | : base(ruleset) 13 | { 14 | } 15 | 16 | protected override HitEvent CreateHitEvent(JudgementResult result) 17 | => base.CreateHitEvent(result).With(new Vector2((result as TauJudgementResult)?.DeltaAngle ?? 0, 0)); 18 | 19 | protected override JudgementResult CreateResult(HitObject hitObject, Judgement judgement) => new TauJudgementResult(hitObject, judgement); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/TauIcons.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics.Sprites; 2 | 3 | namespace osu.Game.Rulesets.Tau 4 | { 5 | public class TauIcons 6 | { 7 | private static IconUsage get(int icon) => new((char)icon, "tauFont"); 8 | 9 | public static IconUsage Tau => get(8284); 10 | 11 | public static IconUsage ModFadeOut => get(8281); 12 | 13 | public static IconUsage ModFadeIn => get(8282); 14 | 15 | public static IconUsage ModInverse => get(8283); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Cursor/AbsoluteCursor.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Containers; 3 | using osuTK; 4 | 5 | namespace osu.Game.Rulesets.Tau.UI.Cursor 6 | { 7 | public partial class AbsoluteCursor : Container 8 | { 9 | public AbsoluteCursor() 10 | { 11 | Size = new Vector2(40); 12 | Origin = Anchor.Centre; 13 | 14 | Child = new CursorPiece(); 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Cursor/CursorPiece.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Containers; 3 | using osu.Framework.Graphics.UserInterface; 4 | 5 | namespace osu.Game.Rulesets.Tau.UI.Cursor 6 | { 7 | public partial class CursorPiece : CompositeDrawable 8 | { 9 | public CursorPiece() 10 | { 11 | RelativeSizeAxes = Axes.Both; 12 | Origin = Anchor.Centre; 13 | Anchor = Anchor.Centre; 14 | 15 | AddRangeInternal(new Drawable[] 16 | { 17 | createProgress(-150), 18 | createProgress(30) 19 | }); 20 | } 21 | 22 | private CircularProgress createProgress(float rotation) 23 | => new() 24 | { 25 | RelativeSizeAxes = Axes.Both, 26 | Anchor = Anchor.Centre, 27 | Origin = Anchor.Centre, 28 | Progress = 0.33, 29 | InnerRadius = 0.1f, 30 | Rotation = rotation 31 | }; 32 | 33 | protected override void UpdateAfterChildren() 34 | { 35 | base.UpdateAfterChildren(); 36 | Rotation += (float)Time.Elapsed / 5; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Cursor/HandlePiece.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using osu.Framework.Graphics; 3 | using osu.Framework.Graphics.Containers; 4 | using osu.Framework.Graphics.Shapes; 5 | using osu.Framework.Input.Events; 6 | using osuTK; 7 | using osuTK.Graphics; 8 | 9 | namespace osu.Game.Rulesets.Tau.UI.Cursor 10 | { 11 | public partial class HandlePiece : CompositeDrawable 12 | { 13 | private readonly Box topLine; 14 | private readonly Box bottomLine; 15 | private readonly CircularContainer circle; 16 | 17 | public HandlePiece() 18 | { 19 | RelativeSizeAxes = Axes.Both; 20 | Anchor = Anchor.Centre; 21 | Origin = Anchor.Centre; 22 | 23 | InternalChildren = new Drawable[] 24 | { 25 | bottomLine = new Box 26 | { 27 | EdgeSmoothness = new Vector2(1f), 28 | Anchor = Anchor.Centre, 29 | Origin = Anchor.BottomCentre, 30 | RelativeSizeAxes = Axes.Y, 31 | Size = new Vector2(1.25f, 0.235f) 32 | }, 33 | topLine = new Box 34 | { 35 | EdgeSmoothness = new Vector2(1f), 36 | Anchor = Anchor.TopCentre, 37 | Origin = Anchor.TopCentre, 38 | RelativeSizeAxes = Axes.Y, 39 | Size = new Vector2(1.25f, 0.235f) 40 | }, 41 | circle = new CircularContainer 42 | { 43 | RelativePositionAxes = Axes.Both, 44 | RelativeSizeAxes = Axes.Both, 45 | Y = -0.25f, 46 | Size = new Vector2(0.03f), 47 | Origin = Anchor.Centre, 48 | Anchor = Anchor.Centre, 49 | Masking = true, 50 | BorderColour = Color4.White, 51 | BorderThickness = 4, 52 | Child = new Box 53 | { 54 | RelativeSizeAxes = Axes.Both, 55 | AlwaysPresent = true, 56 | Alpha = 0, 57 | } 58 | } 59 | }; 60 | } 61 | 62 | protected override bool OnMouseMove(MouseMoveEvent e) 63 | { 64 | circle.Y = -Math.Clamp(Vector2.Distance(AnchorPosition, e.MousePosition) / DrawHeight, 0.015f, 0.45f); 65 | bottomLine.Height = -circle.Y - 0.015f; 66 | topLine.Height = 0.5f + circle.Y - 0.015f; 67 | 68 | return base.OnMouseMove(e); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Cursor/Paddle.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Graphics; 4 | using osu.Framework.Graphics.Containers; 5 | using osu.Framework.Graphics.UserInterface; 6 | 7 | namespace osu.Game.Rulesets.Tau.UI.Cursor 8 | { 9 | public partial class Paddle : Container 10 | { 11 | public const float PADDLE_RADIUS = 0.05f; 12 | 13 | private readonly CircularProgress paddle; 14 | 15 | public Paddle() 16 | { 17 | RelativeSizeAxes = Axes.Both; 18 | Anchor = Anchor.Centre; 19 | Origin = Anchor.Centre; 20 | 21 | Colour = TauPlayfield.ACCENT_COLOUR.Value; 22 | 23 | InternalChildren = new Drawable[] 24 | { 25 | paddle = new CircularProgress 26 | { 27 | RelativeSizeAxes = Axes.Both, 28 | Anchor = Anchor.Centre, 29 | Origin = Anchor.Centre, 30 | Progress = 0, 31 | InnerRadius = PADDLE_RADIUS 32 | }, 33 | new HandlePiece() 34 | }; 35 | } 36 | 37 | private readonly BindableDouble angleRange = new(75); 38 | 39 | [BackgroundDependencyLoader(true)] 40 | private void load(TauCachedProperties props) 41 | { 42 | if (props != null) 43 | angleRange.BindTo(props.AngleRange); 44 | 45 | angleRange.BindValueChanged(r => 46 | { 47 | paddle.Progress = r.NewValue / 360; 48 | paddle.Rotation = (float)(-r.NewValue / 2); 49 | }, true); 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Effects/ClassicKiaiEffect.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Shapes; 3 | using osu.Framework.Utils; 4 | using osuTK; 5 | 6 | namespace osu.Game.Rulesets.Tau.UI.Effects 7 | { 8 | public partial class ClassicKiaiEffect : KiaiEffect 9 | { 10 | public ClassicKiaiEffect(int initialSize) 11 | : base(initialSize) 12 | { 13 | } 14 | 15 | public ClassicKiaiEffect() 16 | : base(20) 17 | { 18 | } 19 | } 20 | 21 | public partial class ClassicEmitter : Emitter 22 | { 23 | protected override Drawable CreateAngularParticle() 24 | => new Triangle 25 | { 26 | Position = Extensions.FromPolarCoordinates(Distance, Settings.Angle) 27 | }; 28 | 29 | protected override Drawable CreateCircularParticle() 30 | => new Triangle 31 | { 32 | Position = Extensions.FromPolarCoordinates( 33 | (RNG.NextSingle() * 0.15f) * 0.15f + Distance, 34 | RNG.NextSingle() * 360f) 35 | }; 36 | 37 | protected override void ApplyHitAnimation(Drawable particle) 38 | { 39 | particle.RotateTo(RNG.NextSingle(-720, 720), Duration) 40 | .FadeOut(Duration, Easing.OutQuint) 41 | .Expire(true); 42 | 43 | if (Settings.IsCircular) 44 | addTransformsForCircular(particle); 45 | else 46 | addTransformsForAngled(particle); 47 | } 48 | 49 | private void addTransformsForAngled(Drawable particle) 50 | { 51 | particle.MoveTo(Extensions.FromPolarCoordinates( 52 | (RNG.NextSingle() * 0.15f) * (Settings.Inversed ? -1f : 1f) + Distance, 53 | RNG.NextSingle(Settings.Angle - 10, Settings.Angle + 10)), 54 | Duration, Easing.OutQuint) 55 | .ResizeTo(new Vector2(RNG.Next(0, 5)), Duration, Easing.OutQuint); 56 | } 57 | 58 | private void addTransformsForCircular(Drawable particle) 59 | { 60 | particle.MoveTo( 61 | Extensions.FromPolarCoordinates( 62 | (RNG.NextSingle() * 0.15f) * (Settings.Inversed ? -1f : 2f) + Distance, 63 | Vector2.Zero.GetDegreesFromPosition(particle.Position)), Duration, 64 | Easing.OutQuint) 65 | .ScaleTo(new Vector2(RNG.Next(1, 2)), Duration, Easing.OutQuint); 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/Effects/KiaiEffectContainer.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Graphics; 4 | using osu.Framework.Graphics.Containers; 5 | using osu.Game.Rulesets.Judgements; 6 | using osu.Game.Rulesets.Objects.Drawables; 7 | using osu.Game.Rulesets.Tau.Configuration; 8 | 9 | namespace osu.Game.Rulesets.Tau.UI.Effects 10 | { 11 | public partial class KiaiEffectContainer : CompositeDrawable 12 | { 13 | private readonly ClassicKiaiEffect classicEffect; 14 | private readonly TurbulenceKiaiEffect turbulenceEffect; 15 | private readonly Bindable kiaiType = new(); 16 | 17 | public KiaiEffectContainer(int initialSize = 20) 18 | { 19 | Anchor = Anchor.Centre; 20 | Origin = Anchor.Centre; 21 | RelativeSizeAxes = Axes.Both; 22 | 23 | InternalChildren = new Drawable[] 24 | { 25 | classicEffect = new ClassicKiaiEffect(initialSize) { Alpha = 0 }, 26 | turbulenceEffect = new TurbulenceKiaiEffect(initialSize) 27 | }; 28 | } 29 | 30 | [BackgroundDependencyLoader(true)] 31 | private void load(TauRulesetConfigManager config) 32 | { 33 | config?.BindWith(TauRulesetSettings.KiaiType, kiaiType); 34 | 35 | kiaiType.BindValueChanged(t => 36 | { 37 | switch (t.NewValue) 38 | { 39 | case KiaiType.Turbulence: 40 | classicEffect.FadeTo(0f, 250, Easing.OutQuint); 41 | turbulenceEffect.FadeTo(1f, 250, Easing.OutQuint); 42 | break; 43 | 44 | case KiaiType.Classic: 45 | classicEffect.FadeTo(1f, 250, Easing.OutQuint); 46 | turbulenceEffect.FadeTo(0f, 250, Easing.OutQuint); 47 | break; 48 | 49 | case KiaiType.None: 50 | default: 51 | classicEffect.FadeTo(0f, 250, Easing.OutQuint); 52 | turbulenceEffect.FadeTo(0f, 250, Easing.OutQuint); 53 | break; 54 | } 55 | }, true); 56 | } 57 | 58 | protected override void LoadComplete() 59 | { 60 | base.LoadComplete(); 61 | kiaiType.TriggerChange(); 62 | } 63 | 64 | public void OnNewResult(DrawableHitObject judgedObject, JudgementResult result) 65 | { 66 | classicEffect.OnNewResult(judgedObject, result); 67 | turbulenceEffect.OnNewResult(judgedObject, result); 68 | } 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/PlayfieldPiece.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Allocation; 2 | using osu.Framework.Bindables; 3 | using osu.Framework.Graphics; 4 | using osu.Framework.Graphics.Containers; 5 | using osu.Framework.Graphics.Shapes; 6 | using osu.Game.Rulesets.Tau.Configuration; 7 | using osuTK.Graphics; 8 | 9 | namespace osu.Game.Rulesets.Tau.UI 10 | { 11 | public partial class PlayfieldPiece : CompositeDrawable 12 | { 13 | private readonly Box background; 14 | private readonly Bindable playfieldDimLevel = new(0.7f); 15 | 16 | public PlayfieldPiece() 17 | { 18 | RelativeSizeAxes = Axes.Both; 19 | 20 | AddInternal(new CircularContainer 21 | { 22 | RelativeSizeAxes = Axes.Both, 23 | Masking = true, 24 | BorderThickness = 3, 25 | BorderColour = TauPlayfield.ACCENT_COLOUR.Value, 26 | Child = background = new Box 27 | { 28 | RelativeSizeAxes = Axes.Both, 29 | Colour = Color4.Black, 30 | Alpha = playfieldDimLevel.Default, 31 | AlwaysPresent = true 32 | } 33 | }); 34 | } 35 | 36 | [Resolved(canBeNull: true)] 37 | private TauRulesetConfigManager config { get; set; } 38 | 39 | protected override void LoadComplete() 40 | { 41 | config?.BindWith(TauRulesetSettings.PlayfieldDim, playfieldDimLevel); 42 | 43 | playfieldDimLevel.BindValueChanged(v => 44 | { 45 | background.FadeTo(v.NewValue, 100); 46 | }, true); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/TauCachedProperties.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Bindables; 2 | using osu.Framework.Graphics.Textures; 3 | using osu.Game.Beatmaps; 4 | using System; 5 | 6 | namespace osu.Game.Rulesets.Tau.UI 7 | { 8 | /// 9 | /// Cached properties for use during gameplay. 10 | /// 11 | public class TauCachedProperties : IDisposable 12 | { 13 | public readonly BindableDouble AngleRange = new(25); 14 | public readonly BindableBool InverseModEnabled = new(); 15 | public Texture SliderTexture; 16 | 17 | /// 18 | /// Sets the range for the paddle. 19 | /// 20 | /// The Circle Size of the beatmap. 21 | public void SetRange(float cs) 22 | { 23 | AngleRange.Value = IBeatmapDifficultyInfo.DifficultyRange(cs, 75, 25, 10); 24 | } 25 | 26 | public void Dispose() 27 | { 28 | SliderTexture?.Dispose(); 29 | SliderTexture = null; 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/TauPlayfieldAdjustmentContainer.cs: -------------------------------------------------------------------------------- 1 | using osu.Framework.Graphics; 2 | using osu.Framework.Graphics.Containers; 3 | using osu.Game.Rulesets.UI; 4 | using osuTK; 5 | 6 | namespace osu.Game.Rulesets.Tau.UI 7 | { 8 | public partial class TauPlayfieldAdjustmentContainer : PlayfieldAdjustmentContainer 9 | { 10 | protected override Container Content => content; 11 | private readonly Container content; 12 | 13 | public TauPlayfieldAdjustmentContainer() 14 | { 15 | Anchor = Anchor.Centre; 16 | Origin = Anchor.Centre; 17 | Size = new Vector2(0.6f); 18 | FillMode = FillMode.Fit; 19 | FillAspectRatio = 1; 20 | 21 | InternalChild = content = new ScalingContainer { RelativeSizeAxes = Axes.Both }; 22 | } 23 | 24 | /// 25 | /// A which scales its content relative to a target width. 26 | /// 27 | private partial class ScalingContainer : Container 28 | { 29 | protected override void Update() 30 | { 31 | base.Update(); 32 | 33 | Scale = new Vector2(Parent.ChildSize.X / TauPlayfield.BASE_SIZE.X); 34 | 35 | Size = Vector2.Divide(Vector2.One, Scale); 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/UI/TauReplayRecorder.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using osu.Game.Rulesets.Replays; 3 | using osu.Game.Rulesets.Tau.Replays; 4 | using osu.Game.Rulesets.UI; 5 | using osu.Game.Scoring; 6 | using osuTK; 7 | 8 | namespace osu.Game.Rulesets.Tau.UI 9 | { 10 | public partial class TauReplayRecorder : ReplayRecorder 11 | { 12 | public TauReplayRecorder(Score score) 13 | : base(score) 14 | { 15 | } 16 | 17 | protected override ReplayFrame HandleFrame(Vector2 mousePosition, List actions, ReplayFrame previousFrame) 18 | => new TauReplayFrame(Time.Current, mousePosition, actions.ToArray()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /osu.Game.Rulesets.Tau/osu.Game.Rulesets.Tau.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net8.0 4 | osu.Game.Rulesets.Tau 5 | Library 6 | AnyCPU 7 | osu.Game.Rulesets.Tau 8 | default 9 | 10 | 11 | osu.Game.Rulesets.Tau 12 | 13 | 14 | 15 | 16 | Beatmap.resx 17 | 18 | 19 | Inputs.resx 20 | 21 | 22 | KiaiType.resx 23 | 24 | 25 | Settings.resx 26 | 27 | 28 | UI.resx 29 | 30 | 31 | Mods.resx 32 | 33 | 34 | UI.resx 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | DrawableSlider.cs 43 | 44 | 45 | DrawableSlider.cs 46 | 47 | 48 | DrawableSlider.Graphics.cs 49 | 50 | 51 | 52 | --------------------------------------------------------------------------------