diff --git a/source/funkin/PauseSubState.hx b/source/funkin/PauseSubState.hx
index f93e5a450..48be31226 100644
--- a/source/funkin/PauseSubState.hx
+++ b/source/funkin/PauseSubState.hx
@@ -16,17 +16,18 @@ class PauseSubState extends MusicBeatSubState
 {
   var grpMenuShit:FlxTypedGroup<Alphabet>;
 
-  var pauseOptionsBase:Array<String> = [
+  final pauseOptionsBase:Array<String> = [
     'Resume',
     'Restart Song',
     'Change Difficulty',
     'Toggle Practice Mode',
     'Exit to Menu'
   ];
+  final pauseOptionsCharting:Array<String> = ['Resume', 'Restart Song', 'Exit to Chart Editor'];
 
-  var pauseOptionsDifficulty:Array<String> = ['EASY', 'NORMAL', 'HARD', 'ERECT', 'BACK'];
+  final pauseOptionsDifficultyBase:Array<String> = ['BACK'];
 
-  var pauseOptionsCharting:Array<String> = ['Resume', 'Restart Song', 'Exit to Chart Editor'];
+  var pauseOptionsDifficulty:Array<String> = []; // AUTO-POPULATED
 
   var menuItems:Array<String> = [];
   var curSelected:Int = 0;
@@ -48,6 +49,12 @@ class PauseSubState extends MusicBeatSubState
     this.isChartingMode = isChartingMode;
 
     menuItems = this.isChartingMode ? pauseOptionsCharting : pauseOptionsBase;
+    var difficultiesInVariation = PlayState.instance.currentSong.listDifficulties(PlayState.instance.currentChart.variation);
+    trace('DIFFICULTIES: ${difficultiesInVariation}');
+
+    pauseOptionsDifficulty = difficultiesInVariation.map(function(item:String):String {
+      return item.toUpperCase();
+    }).concat(pauseOptionsDifficultyBase);
 
     if (PlayStatePlaylist.campaignId == 'week6')
     {
@@ -196,18 +203,6 @@ class PauseSubState extends MusicBeatSubState
             menuItems = pauseOptionsDifficulty;
             regenMenu();
 
-          case 'EASY' | 'NORMAL' | 'HARD' | 'ERECT':
-            PlayState.instance.currentSong = SongRegistry.instance.fetchEntry(PlayState.instance.currentSong.id.toLowerCase());
-
-            PlayState.instance.currentDifficulty = daSelected.toLowerCase();
-
-            PlayState.instance.needsReset = true;
-
-            close();
-          case 'BACK':
-            menuItems = this.isChartingMode ? pauseOptionsCharting : pauseOptionsBase;
-            regenMenu();
-
           case 'Toggle Practice Mode':
             PlayState.instance.isPracticeMode = true;
             practiceText.visible = PlayState.instance.isPracticeMode;
@@ -237,6 +232,30 @@ class PauseSubState extends MusicBeatSubState
             this.close();
             if (FlxG.sound.music != null) FlxG.sound.music.stop();
             PlayState.instance.close(); // This only works because PlayState is a substate!
+
+          case 'BACK':
+            menuItems = this.isChartingMode ? pauseOptionsCharting : pauseOptionsBase;
+            regenMenu();
+
+          default:
+            if (pauseOptionsDifficulty.contains(daSelected))
+            {
+              PlayState.instance.currentSong = SongRegistry.instance.fetchEntry(PlayState.instance.currentSong.id.toLowerCase());
+
+              // Reset campaign score when changing difficulty
+              // So if you switch difficulty on the last song of a week you get a really low overall score.
+              PlayStatePlaylist.campaignScore = 0;
+              PlayStatePlaylist.campaignDifficulty = daSelected.toLowerCase();
+              PlayState.instance.currentDifficulty = PlayStatePlaylist.campaignDifficulty;
+
+              PlayState.instance.needsReset = true;
+
+              close();
+            }
+            else
+            {
+              trace('[WARN] Unhandled pause menu option: ${daSelected}');
+            }
         }
       }
 
diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx
index d7c2a2a4c..9e1c89c8a 100644
--- a/source/funkin/play/PlayState.hx
+++ b/source/funkin/play/PlayState.hx
@@ -2419,7 +2419,7 @@ class PlayState extends MusicBeatSubState
         if (currentSong.validScore)
         {
           NGio.unlockMedal(60961);
-          Highscore.saveWeekScoreForDifficulty(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignScore, currentDifficulty);
+          Highscore.saveWeekScoreForDifficulty(PlayStatePlaylist.campaignId, PlayStatePlaylist.campaignScore, PlayStatePlaylist.campaignDifficulty);
         }
 
         // FlxG.save.data.weekUnlocked = StoryMenuState.weekUnlocked;
@@ -2466,7 +2466,7 @@ class PlayState extends MusicBeatSubState
             var nextPlayState:PlayState = new PlayState(
               {
                 targetSong: targetSong,
-                targetDifficulty: currentDifficulty,
+                targetDifficulty: PlayStatePlaylist.campaignDifficulty,
                 targetCharacter: currentPlayerId,
               });
             nextPlayState.previousCameraFollowPoint = new FlxSprite(cameraFollowPoint.x, cameraFollowPoint.y);
@@ -2482,7 +2482,7 @@ class PlayState extends MusicBeatSubState
           var nextPlayState:PlayState = new PlayState(
             {
               targetSong: targetSong,
-              targetDifficulty: currentDifficulty,
+              targetDifficulty: PlayStatePlaylist.campaignDifficulty,
               targetCharacter: currentPlayerId,
             });
           nextPlayState.previousCameraFollowPoint = new FlxSprite(cameraFollowPoint.x, cameraFollowPoint.y);
@@ -2608,7 +2608,12 @@ class PlayState extends MusicBeatSubState
             persistentUpdate = false;
             vocals.stop();
             camHUD.alpha = 1;
-            var res:ResultState = new ResultState();
+            var res:ResultState = new ResultState(
+              {
+                storyMode: PlayStatePlaylist.isStoryMode,
+                title: PlayStatePlaylist.isStoryMode ? ('${PlayStatePlaylist.campaignTitle}') : ('${currentChart.songName} by ${currentChart.songArtist}'),
+                tallies: Highscore.tallies,
+              });
             res.camera = camHUD;
             openSubState(res);
           }
diff --git a/source/funkin/play/PlayStatePlaylist.hx b/source/funkin/play/PlayStatePlaylist.hx
index 6b754878c..3b0fb01f6 100644
--- a/source/funkin/play/PlayStatePlaylist.hx
+++ b/source/funkin/play/PlayStatePlaylist.hx
@@ -34,10 +34,7 @@ class PlayStatePlaylist
    */
   public static var campaignId:String = 'unknown';
 
-  /**
-   * The current difficulty selected for this level (as a named ID).
-   */
-  public static var currentDifficulty(default, default):String = Constants.DEFAULT_DIFFICULTY;
+  public static var campaignDifficulty:String = Constants.DEFAULT_DIFFICULTY;
 
   /**
    * Resets the playlist to its default state.
@@ -49,6 +46,6 @@ class PlayStatePlaylist
     campaignScore = 0;
     campaignTitle = 'UNKNOWN';
     campaignId = 'unknown';
-    currentDifficulty = Constants.DEFAULT_DIFFICULTY;
+    campaignDifficulty = Constants.DEFAULT_DIFFICULTY;
   }
 }
diff --git a/source/funkin/play/ResultState.hx b/source/funkin/play/ResultState.hx
index 0c2984719..3f7231c2a 100644
--- a/source/funkin/play/ResultState.hx
+++ b/source/funkin/play/ResultState.hx
@@ -22,6 +22,8 @@ import flxanimate.FlxAnimate.Settings;
 
 class ResultState extends MusicBeatSubState
 {
+  final params:ResultsStateParams;
+
   var resultsVariation:ResultVariations;
   var songName:FlxBitmapText;
   var difficulty:FlxSprite;
@@ -29,13 +31,18 @@ class ResultState extends MusicBeatSubState
   var maskShaderSongName = new LeftMaskShader();
   var maskShaderDifficulty = new LeftMaskShader();
 
+  public function new(params:ResultsStateParams)
+  {
+    super();
+
+    this.params = params;
+  }
+
   override function create():Void
   {
-    if (Highscore.tallies.sick == Highscore.tallies.totalNotesHit
-      && Highscore.tallies.maxCombo == Highscore.tallies.totalNotesHit) resultsVariation = PERFECT;
-    else if (Highscore.tallies.missed
-      + Highscore.tallies.bad
-      + Highscore.tallies.shit >= Highscore.tallies.totalNotes * 0.50)
+    if (params.tallies.sick == params.tallies.totalNotesHit
+      && params.tallies.maxCombo == params.tallies.totalNotesHit) resultsVariation = PERFECT;
+    else if (params.tallies.missed + params.tallies.bad + params.tallies.shit >= params.tallies.totalNotes * 0.50)
       resultsVariation = SHIT; // if more than half of your song was missed, bad, or shit notes, you get shit ending!
     else
       resultsVariation = NORMAL;
@@ -135,17 +142,7 @@ class ResultState extends MusicBeatSubState
 
     var fontLetters:String = "AaBbCcDdEeFfGgHhiIJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz:1234567890";
     songName = new FlxBitmapText(FlxBitmapFont.fromMonospace(Paths.image("resultScreen/tardlingSpritesheet"), fontLetters, FlxPoint.get(49, 62)));
-
-    // stole this from PauseSubState, I think eric wrote it!!
-    if (PlayState.instance.currentChart != null)
-    {
-      songName.text += '${PlayState.instance.currentChart.songName}:${PlayState.instance.currentChart.songArtist}';
-    }
-    else
-    {
-      songName.text += PlayState.instance.currentSong.id;
-    }
-
+    songName.text = params.title;
     songName.letterSpacing = -15;
     songName.angle = -4.1;
     add(songName);
@@ -194,27 +191,27 @@ class ResultState extends MusicBeatSubState
     var ratingGrp:FlxTypedGroup<TallyCounter> = new FlxTypedGroup<TallyCounter>();
     add(ratingGrp);
 
-    var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, Highscore.tallies.totalNotesHit);
+    var totalHit:TallyCounter = new TallyCounter(375, hStuf * 3, params.tallies.totalNotesHit);
     ratingGrp.add(totalHit);
 
-    var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, Highscore.tallies.maxCombo);
+    var maxCombo:TallyCounter = new TallyCounter(375, hStuf * 4, params.tallies.maxCombo);
     ratingGrp.add(maxCombo);
 
     hStuf += 2;
     var extraYOffset:Float = 5;
-    var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, Highscore.tallies.sick, 0xFF89E59E);
+    var tallySick:TallyCounter = new TallyCounter(230, (hStuf * 5) + extraYOffset, params.tallies.sick, 0xFF89E59E);
     ratingGrp.add(tallySick);
 
-    var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, Highscore.tallies.good, 0xFF89C9E5);
+    var tallyGood:TallyCounter = new TallyCounter(210, (hStuf * 6) + extraYOffset, params.tallies.good, 0xFF89C9E5);
     ratingGrp.add(tallyGood);
 
-    var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, Highscore.tallies.bad, 0xffE6CF8A);
+    var tallyBad:TallyCounter = new TallyCounter(190, (hStuf * 7) + extraYOffset, params.tallies.bad, 0xffE6CF8A);
     ratingGrp.add(tallyBad);
 
-    var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, Highscore.tallies.shit, 0xFFE68C8A);
+    var tallyShit:TallyCounter = new TallyCounter(220, (hStuf * 8) + extraYOffset, params.tallies.shit, 0xFFE68C8A);
     ratingGrp.add(tallyShit);
 
-    var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, Highscore.tallies.missed, 0xFFC68AE6);
+    var tallyMissed:TallyCounter = new TallyCounter(260, (hStuf * 9) + extraYOffset, params.tallies.missed, 0xFFC68AE6);
     ratingGrp.add(tallyMissed);
 
     for (ind => rating in ratingGrp.members)
@@ -275,7 +272,7 @@ class ResultState extends MusicBeatSubState
       }
     });
 
-    if (Highscore.tallies.isNewHighscore) trace("ITS A NEW HIGHSCORE!!!");
+    if (params.tallies.isNewHighscore) trace("ITS A NEW HIGHSCORE!!!");
 
     super.create();
   }
@@ -351,7 +348,7 @@ class ResultState extends MusicBeatSubState
 
     if (controls.PAUSE)
     {
-      if (PlayStatePlaylist.isStoryMode)
+      if (params.storyMode)
       {
         FlxG.switchState(new StoryMenuState());
       }
@@ -372,3 +369,21 @@ enum abstract ResultVariations(String)
   var NORMAL;
   var SHIT;
 }
+
+typedef ResultsStateParams =
+{
+  /**
+   * True if results are for a level, false if results are for a single song.
+   */
+  var storyMode:Bool;
+
+  /**
+   * Either "Song Name by Artist Name" or "Week Name"
+   */
+  var title:String;
+
+  /**
+   * The score, accuracy, and judgements.
+   */
+  var tallies:Highscore.Tallies;
+};
diff --git a/source/funkin/play/song/Song.hx b/source/funkin/play/song/Song.hx
index d11c7744b..96eb434d2 100644
--- a/source/funkin/play/song/Song.hx
+++ b/source/funkin/play/song/Song.hx
@@ -56,8 +56,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
    */
   public var validScore:Bool = true;
 
-  var difficultyIds:Array<String>;
-
   public var songName(get, never):String;
 
   function get_songName():String
@@ -85,7 +83,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
     this.id = id;
 
     variations = [];
-    difficultyIds = [];
     difficulties = new Map<String, SongDifficulty>();
 
     _data = _fetchData(id);
@@ -127,8 +124,7 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
     for (vari in variations)
       result.variations.push(vari);
 
-    result.difficultyIds.clear();
-
+    result.difficulties.clear();
     result.populateDifficulties();
 
     for (variation => chartData in charts)
@@ -162,8 +158,6 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
       // but all the difficulties in the metadata must be in the chart file.
       for (diffId in metadata.playData.difficulties)
       {
-        difficultyIds.push(diffId);
-
         var difficulty:SongDifficulty = new SongDifficulty(this, diffId, metadata.variation);
 
         variations.push(metadata.variation);
@@ -237,19 +231,33 @@ class Song implements IPlayStateScriptedClass implements IRegistryEntry<SongMeta
    */
   public inline function getDifficulty(?diffId:String):Null<SongDifficulty>
   {
-    if (diffId == null) diffId = difficulties.keys().array()[0];
+    if (diffId == null) diffId = listDifficulties()[0];
 
     return difficulties.get(diffId);
   }
 
-  public function listDifficulties():Array<String>
+  /**
+   * List all the difficulties in this song.
+   * @param variationId Optionally filter by variation.
+   * @return The list of difficulties.
+   */
+  public function listDifficulties(?variationId:String):Array<String>
   {
-    return difficultyIds;
+    if (variationId == '') variationId = null;
+
+    return difficulties.keys().array().filter(function(diffId:String):Bool {
+      if (variationId == null) return true;
+      var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
+      if (difficulty == null) return false;
+      return difficulty.variation == variationId;
+    });
   }
 
-  public function hasDifficulty(diffId:String):Bool
+  public function hasDifficulty(diffId:String, ?variationId:String):Bool
   {
-    return difficulties.exists(diffId);
+    if (variationId == '') variationId = null;
+    var difficulty:Null<SongDifficulty> = difficulties.get(diffId);
+    return variationId == null ? (difficulty != null) : (difficulty != null && difficulty.variation == variationId);
   }
 
   /**
diff --git a/source/funkin/ui/story/StoryMenuState.hx b/source/funkin/ui/story/StoryMenuState.hx
index 3a5a388a8..35a5b6479 100644
--- a/source/funkin/ui/story/StoryMenuState.hx
+++ b/source/funkin/ui/story/StoryMenuState.hx
@@ -521,6 +521,7 @@ class StoryMenuState extends MusicBeatState
 
     PlayStatePlaylist.campaignId = currentLevel.id;
     PlayStatePlaylist.campaignTitle = currentLevel.getTitle();
+    PlayStatePlaylist.campaignDifficulty = currentDifficultyId;
 
     if (targetSong != null)
     {
@@ -536,7 +537,7 @@ class StoryMenuState extends MusicBeatState
       LoadingState.loadAndSwitchState(new PlayState(
         {
           targetSong: targetSong,
-          targetDifficulty: currentDifficultyId,
+          targetDifficulty: PlayStatePlaylist.campaignDifficulty,
         }), true);
     });
   }