public static double GetPlotForRoom(int ID, Routes.GameRoutes route) { double plot = 0; foreach (var room in plotDict) { if (room.Key <= ID) { if (route != Routes.GameRoutes.Genocide) { plot = room.Value.Item1; } else { plot = room.Value.Item2; } } else if (room.Key > ID) { break; } } return(plot); }
//SetINIForRoute sets the appropriate INI file values for the player's route and location public static INIFile SetINIForRoute(int locationID, Routes.GameRoutes routeToSet) { if (routeToSet >= Routes.GameRoutes.TruePacifistDate) { staticINIFile.skipAsrielStory = true; staticINIFile.floweyChatProgress = 1; staticINIFile.mettatonSkip = true; staticINIFile.fightStage = 7; if (routeToSet == Routes.GameRoutes.TruePacifistEpilogue) { staticINIFile.barrierDestroyed = true; staticINIFile.canTrueReset = true; } } else if (routeToSet == Routes.GameRoutes.Genocide) { staticINIFile.killedSans = MiscFunctions.SetBooleanValueFromLocation(locationID, 231); staticINIFile.timesReachedMid = SetIntegerValue(1, locationID, 231); staticINIFile.timesFoughtSans = SetIntegerValue(1, locationID, 231); staticINIFile.timesHeardIntro = SetIntegerValue(1, locationID, 231); } staticINIFile.timesMetFlowey = SetIntegerValue(1, locationID, 5); staticINIFile.timesMetSans = SetIntegerValue(1, locationID, 45); staticINIFile.timesMetPapyrus = SetIntegerValue(1, locationID, 45); staticINIFile.mettatonSkip = Convert.ToBoolean(SetIntegerValue(1, locationID, 211)); staticINIFile.sansMetInJudgment = Convert.ToBoolean(SetIntegerValue(1, locationID, 231)); return(staticINIFile); }
//SetPhoneItems sets the appropriate phone items for the player's currentLocation and their currentRoute //This can be overridden by the user if they change the CheckBoxes manually in the Editor UI private static void SetPhoneItems(int currentLocation, Routes.GameRoutes currentRoute) { int i = 0; Array.Clear(SAVEInstance.phoneItems, 0, SAVEInstance.phoneItems.Length); if (currentLocation > 11) { //We are past the Tension room so we add Toriel's number SAVEInstance.phoneItems[i] = 206; i++; if ((currentLocation > 142 && currentRoute != Routes.GameRoutes.QueenAlphys && currentRoute != Routes.GameRoutes.Genocide) || currentRoute >= Routes.GameRoutes.TruePacifistDate) { //We've passed the Hotland Lab on an appropriate route so we add the Dimensional Boxes SAVEInstance.phoneItems[i] = 220; i++; SAVEInstance.phoneItems[i] = 221; i++; } } if ((SAVEInstance.papyrusDated == DateStates.PapyrusComplete && SAVEInstance.papyrusState != CharacterStates.Killed) || currentRoute >= Routes.GameRoutes.TruePacifistDate) { //Papyrus isn't dead and has been dated so we add his number SAVEInstance.phoneItems[i] = 210; } }
//updateCurrentRoute sets up the UI, SAVE and INI files, as well as the selectedRoute when the game route is changed via the UI void updateCurrentRoute() { makeSave(); Routes.GameRoutes selectedRoute = GetSelectedRoute(); thisSave = SAVE.SAVEFile.SetSaveForRoute(thisSave, IDs.Locations.GetRoomID(locationCombo.SelectedItem.ToString()), selectedRoute); thisINI = INI.SetINIForRoute(IDs.Locations.GetRoomID(locationCombo.SelectedItem.ToString()), selectedRoute); loadSAVE(thisSave); loadINI(); LOVEChanged(); }
//We use the loadButton_Click event to open a new folder browser to allow the user to load a save and set up the UI for the loaded save private void loadButton_Click(object sender, RoutedEventArgs e) { FolderBrowser2 directoryFolderBrowser = new FolderBrowser2(); directoryFolderBrowser.ShowDialog(null); if (File.Exists(directoryFolderBrowser.DirectoryPath + "//file0")) { SAVE.SAVEFile saveFile = SAVE.SAVEFile.LoadSaveFile(directoryFolderBrowser.DirectoryPath); loadSAVE(saveFile); thisINI = INI.ReadINI(saveFile); loadINI(); Routes.GameRoutes closestRoute = SAVE.SAVEFile.GetClosestRoute(saveFile); if (closestRoute == Routes.GameRoutes.Genocide) { genocideRadio.IsChecked = true; } else if (closestRoute >= Routes.GameRoutes.TruePacifistDate) { pacifistRadio.IsChecked = true; routeCombo.SelectedItem = Routes.GetEnumDescription(SAVE.SAVEFile.GetClosestRoute(thisSave)); } else { neutralRadio.IsChecked = true; routeCombo.SelectedItem = Routes.GetEnumDescription(SAVE.SAVEFile.GetClosestRoute(thisSave)); } MXA2SE.play_sound(soundEngine, "Assets//Sounds//fileLoaded.wav"); } else { Dictionary <Characters, string> messageDict = new Dictionary <Characters, string>() { { Characters.Alphys, "S-s-sorry, that folder doesn't contain a valid Undertale save file." }, { Characters.Asgore, "Human, I'm sorry, but folder doesn't contain a valid Undertale save file." }, { Characters.Asriel, "I'm really sorry, I tried, but couldn't find a valid Undertale save file in that folder." }, { Characters.Flowey, "YOU. IDIOT! That folder doesn't contain a valid Undertale save file!" }, { Characters.Papyrus, "NYOO HOO HOO. I, THE GREAT PAPYRUS, HAVE FAILED TO FIND A VALID SAVE FILE IN THAT FOLDER." }, { Characters.Sans, "heyo, pal. try again. i couldn't find an Undertale save file in that folder." }, { Characters.Toriel, "My child, I am sorry, but I was unable to find a valid Undertale save file in that folder." }, { Characters.Undyne, "HEY, PUNK! I CAN'T FIND AN UNDERTALE SAVE FILE IN THAT FOLDER!" }, { Characters.None, "The folder specified does not contain a valid Undertale save file!" } }; UTMessageBox.Show(messageDict, Constants.CharacterReactions.Negative, MessageBoxButton.OK); } }
//SetPlotValue sets the appropriate plot value based on the player's route and their currentLocation private static void SetPlotValue(Routes.GameRoutes route, int currentLocation) { if (route >= Routes.GameRoutes.TruePacifistDate && route < Routes.GameRoutes.TruePacifistEpilogue) { SAVEInstance.Plot = 208; } else if (route == Routes.GameRoutes.TruePacifistEpilogue) { SAVEInstance.Plot = 999; } else { SAVEInstance.Plot = IDs.Locations.GetPlotForRoom(currentLocation, route); } }
//SetSaveForRoute sets the variable values needed for each route's requirements to be met up to the player's currentLocation public static SAVEFile SetSaveForRoute(SAVEFile save, int locationID, Routes.GameRoutes routeToSet) { //It is key to note we assume the maximum kill count allowed for each route, regardless of location //This shouldn't be too big of an issue as the user can manually change their kills via the Editor UI SAVEInstance = save; clearStates(locationID); SAVEInstance.rodeCastleLift = MiscFunctions.SetBooleanValueFromLocation(locationID, 216); SAVEInstance.unlockedCastleChain = MiscFunctions.SetBooleanValueFromLocation(locationID, 226); SAVEInstance.insideCastle = MiscFunctions.SetBooleanValueFromLocation(locationID, 216); SAVEInstance.coreElevatorUnlocked = MiscFunctions.SetBooleanValueFromLocation(locationID, 210); switch (routeToSet) { case Routes.GameRoutes.Family: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel, Characters.Papyrus); SetDateValue(locationID, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(locationID, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.undyneOnPhone = MiscFunctions.SetBooleanValueFromLocation(locationID, 139); SAVEInstance.KillCount = 0; break; case Routes.GameRoutes.BetrayedUndyneDated: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel, Characters.Papyrus); SetDateValue(locationID, Characters.Undyne, DateStates.UndyneComplete); SetDateValue(locationID, Characters.Papyrus, DateStates.PapyrusComplete); SAVEInstance.undyneOnPhone = MiscFunctions.SetBooleanValueFromLocation(locationID, 139); SAVEInstance.KillCount = 9; break; case Routes.GameRoutes.BetrayedUndyneNoDate: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel, Characters.Papyrus); SetDateValue(locationID, Characters.Undyne, DateStates.DateNotStarted); SetDateValue(locationID, Characters.Papyrus, DateStates.PapyrusComplete); SAVEInstance.KillCount = 9; break; case Routes.GameRoutes.BetrayedUndyneMettaton: SetDateValue(locationID, Characters.Undyne, DateStates.DateNotStarted); SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel, Characters.Papyrus); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Mettaton); SAVEInstance.KillCount = 1; break; case Routes.GameRoutes.ExiledNoUndyneNoPapyrus: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Papyrus, Characters.Undyne); SAVEInstance.KillCount = 2; break; case Routes.GameRoutes.ExiledNoUndynePapyrus: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel, Characters.Papyrus); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Undyne); SAVEInstance.KillCount = 1; break; case Routes.GameRoutes.ExiledUndyneNoPapyrus: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Toriel); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Papyrus); SAVEInstance.KillCount = 1; break; case Routes.GameRoutes.ExiledMonsters: SAVEInstance.KillCount = 10; break; case Routes.GameRoutes.QueenUndyne: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Papyrus); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel); SAVEInstance.KillCount = 1; break; case Routes.GameRoutes.QueenUndyneNoPapyrus: SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Papyrus); SAVEInstance.KillCount = 2; break; case Routes.GameRoutes.KingMettaton: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Papyrus); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Undyne); SAVEInstance.KillCount = 2; break; case Routes.GameRoutes.KingMettatonNoPapyrus: SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Undyne, Characters.Papyrus); SAVEInstance.KillCount = 3; break; case Routes.GameRoutes.KingPapyrus: SetCharacterStates(locationID, CharacterStates.Spared, Characters.Papyrus); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Undyne, Characters.Mettaton); SAVEInstance.KillCount = 3; break; case Routes.GameRoutes.KingDog: SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Undyne, Characters.Mettaton, Characters.Papyrus); SAVEInstance.KillCount = 4; break; case Routes.GameRoutes.Leaderless: SetCharacterStates(locationID, CharacterStates.Killed, Characters.Toriel, Characters.Undyne, Characters.Mettaton, Characters.Papyrus, Characters.RuinsDummy, Characters.Doggo, Characters.Shyren, Characters.BroGuards); SAVEInstance.KillCount = 8; break; case Routes.GameRoutes.QueenAlphys: SetMurderLevel(locationID, 12); SetCharacterStates(locationID, CharacterStates.Killed, Characters.Mettaton); SAVEInstance.KillCount = SAVEInstance.KillCount + 1; //We add one to account for Mettaton being killed break; case Routes.GameRoutes.Genocide: SetMurderLevel(locationID, 16); SAVEInstance.disableAlphysCalls = MiscFunctions.SetBooleanValueFromLocation(locationID, 133); SAVEInstance.disableHotlandPuzzles = MiscFunctions.SetBooleanValueFromLocation(locationID, 133); SAVEInstance.coreElevatorUnlocked = MiscFunctions.SetBooleanValueFromLocation(locationID, 133); SAVEInstance.randomCountersDisabled = MiscFunctions.SetBooleanValueFromLocation(locationID, 212); break; case Routes.GameRoutes.TruePacifistDate: SetCharacterStates(locationID, CharacterStates.Spared, Characters.All); //These used to be just Toriel and Papyrus! Any reason? SetDateValue(236, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(236, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.pacifistStage = 2; SAVEInstance.Location = 236; SAVEInstance.dateAlphysFlag = true; SAVEInstance.rodeCastleLift = true; SAVEInstance.unlockedCastleChain = true; SAVEInstance.undyneOnPhone = true; break; case Routes.GameRoutes.TruePacifistLab: SetCharacterStates(locationID, CharacterStates.Spared, Characters.All); SetDateValue(236, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(236, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.pacifistStage = 11; SAVEInstance.Location = 139; SAVEInstance.rodeCastleLift = true; SAVEInstance.unlockedCastleChain = true; SAVEInstance.undyneOnPhone = true; SAVEInstance.randomCountersDisabled = true; break; case Routes.GameRoutes.TruePacifistAsriel: SetCharacterStates(locationID, CharacterStates.Spared, Characters.All); SetDateValue(236, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(236, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.pacifistStage = 12; SAVEInstance.Location = 216; SAVEInstance.rodeCastleLift = true; SAVEInstance.unlockedCastleChain = true; SAVEInstance.beatTrueLab = true; SAVEInstance.undyneOnPhone = true; SAVEInstance.randomCountersDisabled = true; break; case Routes.GameRoutes.TruePacifistAsrielTalk: SetCharacterStates(locationID, CharacterStates.Spared, Characters.All); SetDateValue(236, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(236, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.pacifistStage = 12; SAVEInstance.Location = 331; SAVEInstance.rodeCastleLift = true; SAVEInstance.unlockedCastleChain = true; SAVEInstance.beatTrueLab = true; SAVEInstance.undyneOnPhone = true; SAVEInstance.randomCountersDisabled = true; break; case Routes.GameRoutes.TruePacifistEpilogue: SetCharacterStates(locationID, CharacterStates.Spared, Characters.All); SetDateValue(236, Characters.Papyrus, DateStates.PapyrusComplete); SetDateValue(236, Characters.Undyne, DateStates.UndyneComplete); SAVEInstance.pacifistStage = 12; SAVEInstance.Location = 236; SAVEInstance.rodeCastleLift = true; SAVEInstance.unlockedCastleChain = true; SAVEInstance.beatTrueLab = true; SAVEInstance.asrielDefeated = true; SAVEInstance.undyneOnPhone = true; SAVEInstance.randomCountersDisabled = true; break; } SetPhoneItems(locationID, routeToSet); SetPlotValue(routeToSet, locationID); return(SAVEInstance); }
//SetDateValue sets the corresponding character to the date state passed in. Consult IDs.cs to see the DateStates enum private static void SetDateValue(int currentLocation, Characters character, DateStates stateToSet, Routes.GameRoutes route = Routes.GameRoutes.Family) { //We call CheckRoomForDate to see if the character's date state would be invalid at the player's currentLocation //i.e. Undyne cannot possibly be dated if we're still in Snowdin, so if that's the case, we set the stateToSet to DateNotStarted if (!Routes.CheckRoomForDate(currentLocation, character, route)) { stateToSet = DateStates.DateNotStarted; } switch (character) { case Characters.Papyrus: SAVEInstance.papyrusDated = stateToSet; break; case Characters.Undyne: SAVEInstance.undyneDated = stateToSet; break; } }
//GetClosestEnding checks variables within the SAVEFile and returns the route that most closely matches the SAVEFile content public static Routes.GameRoutes GetClosestRoute(SAVEFile actualSave) { Dictionary <Routes.GameRoutes, int> likenessDict = new Dictionary <Routes.GameRoutes, int>(); int likeness = 0; if (actualSave.pacifistStage == 2) { return(Routes.GameRoutes.TruePacifistDate); } else if (actualSave.pacifistStage == 11) { return(Routes.GameRoutes.TruePacifistLab); } else if (actualSave.pacifistStage == 12) { if (actualSave.Location == 331) { return(Routes.GameRoutes.TruePacifistAsrielTalk); } else if (actualSave.asrielDefeated) { return(Routes.GameRoutes.TruePacifistEpilogue); } else { return(Routes.GameRoutes.TruePacifistAsriel); } } else if (actualSave.disableAlphysCalls && actualSave.disableHotlandPuzzles) { return(Routes.GameRoutes.Genocide); } else { Routes.GameRoutes[] routesToIgnore = new Routes.GameRoutes[] { Routes.GameRoutes.TruePacifistDate, Routes.GameRoutes.TruePacifistLab, Routes.GameRoutes.TruePacifistAsriel, Routes.GameRoutes.TruePacifistAsrielTalk, Routes.GameRoutes.TruePacifistEpilogue }; foreach (Routes.GameRoutes route in Enum.GetValues(typeof(Routes.GameRoutes))) { if (!routesToIgnore.Contains(route)) { SAVEFile compareSave = new SAVEFile(); compareSave = SetSaveForRoute(compareSave, actualSave.Location, route); foreach (var actualCharacterState in compareSave.GetType().GetProperties()) { foreach (CharacterStates stateToCheck in Enum.GetValues(typeof(CharacterStates))) { if ((CharacterStates)actualCharacterState.GetValue(actualCharacterState) == stateToCheck) { likeness++; } } } foreach (var actualDateState in compareSave.GetType().GetProperties()) { foreach (DateStates stateToCheck in Enum.GetValues(typeof(DateStates))) { if ((DateStates)actualDateState.GetValue(actualDateState) == stateToCheck) { likeness++; } } } if (compareSave.KillCount <= actualSave.KillCount) { likeness++; } if (Routes.GetMurderLevelForLocation(compareSave.Location, 16) == Routes.GetMurderLevelForLocation(actualSave.Location, 16)) { likeness++; } likenessDict.Add(route, likeness); likeness = 0; } } } return(likenessDict.Where(key => key.Value == likenessDict.Max(value => value.Value)).Select(key => key.Key).FirstOrDefault()); }