//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); } }
//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(); }
//AskToWrite is called when we want to write our SAVEFile classes's variables to file0. It checks if the directory to write to //already exists and asks the user if they wish to overwrite. It then calls WriteSaveFile and WriteINI with the relevant arguments passed public static bool AskToWrite(SAVEFile thisSave, INI.INIFile thisINI) { if (!Directory.Exists(Constants.SavesPath + thisSave.SaveName)) { Directory.CreateDirectory(Constants.SavesPath + thisSave.SaveName); if (!WriteSaveFile(thisSave, thisINI) || !INI.WriteINI(thisINI, thisSave)) { return(false); } return(true); } else { Dictionary <Characters, string> messageDict = new Dictionary <Characters, string>() { { Characters.Alphys, "Hey! So, the save \"" + thisSave.SaveName + "\" already exists. Would you like me to overwrite it?" }, { Characters.Asgore, "Well human, the save \"" + thisSave.SaveName + "\" already exists. Shall I overwrite it?" }, { Characters.Asriel, "Sorry, but the save \"" + thisSave.SaveName + "\" already exists. Do you want me to overwrite it? It's no trouble, really!" }, { Characters.Flowey, "YOU. IDIOT! The save \"" + thisSave.SaveName + "\" already exists. Of course, I've got to do all the work - do you want me to overwrite it?" }, { Characters.Papyrus, "NYEH, SORRY HUMAN. THE SAVE \"" + thisSave.SaveName + "\" ALREADY EXISTS. WOULD YOU LIKE ME TO ASSIST YOU AND OVERWRITE IT?" }, { Characters.Sans, "yo, buddy. the save \"" + thisSave.SaveName + "\" already exists. i'm normally quite lazy, but i'll make an exception for ya. want me to overwrite it?" }, { Characters.Toriel, "My child, I apologize, but the save \"" + thisSave.SaveName + "\" already exists. Would you like me to overwrite it for you?" }, { Characters.Undyne, "OH COME ON. The save \"" + thisSave.SaveName + "\" already exists. Want me to overwrite it?" }, { Characters.None, "Save \"" + thisSave.SaveName + "\" already exists! Do you want to overwrite?" } }; MessageBoxResult res = UTMessageBox.Show(messageDict, Constants.CharacterReactions.Normal, MessageBoxButton.YesNo); if (res == MessageBoxResult.Yes) { if (!WriteSaveFile(thisSave, thisINI) || !INI.WriteINI(thisINI, thisSave)) { return(false); } return(true); } return(false); } }
//loadINI is responsible for setting up the UI based on the variable values of thisINI private void loadINI() { thisINI = INI.GetINI(); playedBox.Text = thisINI.timePlayed.ToString(); deathsBox.Text = thisINI.deaths.ToString(); FUNBox.Text = thisINI.FUN.ToString(); asrielCheck.IsChecked = thisINI.skipAsrielStory; resetCheck.IsChecked = thisINI.trueResetted; doorCheck.IsChecked = thisINI.doorUnlocked; floweyMetBox.Text = thisINI.timesMetFlowey.ToString(); floweyChatCombo.SelectedIndex = thisINI.floweyChatProgress; pieCombo.SelectedIndex = thisINI.piePreference - 1; sansMetBox.Text = thisINI.timesMetSans.ToString(); sansPasswordCombo.SelectedIndex = thisINI.sansPasswordProgress; papyrusMetBox.Text = thisINI.timesMetPapyrus.ToString(); skipTurnCheck.IsChecked = thisINI.mettatonSkip; fightCombo.SelectedIndex = thisINI.fightStage; skipPhotoshopCheck.IsChecked = thisINI.skipFight; }
//We use the Window_Loaded event to create new instances of our SAVEFile and INI file classes, as well as populating our UI controls and item dicts private void SharpWindow_Loaded(object sender, RoutedEventArgs e) { loading = true; thisSave = new SAVE.SAVEFile(); thisINI = new INI.INIFile(); IDs.Weapons.populateDictionary(); IDs.Armors.populateDictionary(); IDs.Items.populateDictionary(); IDs.PhoneItems.populateDictionary(); IDs.InventoryItems.populateDictionary(); IDs.Locations.populateDictionary(); Stats.populateDictionary(); populateAllCombos(); setDefaultValues(); thisINI = INI.GetINI(); loadINI(); loading = false; }
//makeSave loops through all UI controls and converts and casts to thisSave variable types as required to create a new save void makeSave() { thisSave.PlayerName = nameBox.Text; thisSave.Location = IDs.Locations.GetRoomID(locationCombo.SelectedItem.ToString()); thisSave.LOVE = Convert.ToInt16(LOVECombo.Text); thisSave.KillCount = Convert.ToInt16(killsBox.Text); thisSave.GOLD = Convert.ToInt16(GOLDBox.Text); thisSave.Weapon = IDs.GetID(weaponCombo.SelectedItem.ToString()); thisSave.Armor = IDs.GetID(armorCombo.SelectedItem.ToString()); thisSave.HP = Convert.ToInt16(HPBox.Text); thisSave.friskAT = Convert.ToInt16(friskATBox.Text) + 10; //For some reason, the game sets Frisk's base AT to -10 of what is set in the thisSave.friskDF = Convert.ToInt16(friskDFBox.Text) + 10; //save file. Am I missing something regarding the AT/DF system? thisSave.weaponAT = Convert.ToInt16(weaponATBox.Text); thisSave.armorDF = Convert.ToInt16(armorDFBox.Text); int i = 0; Array.Clear(thisSave.inventoryItems, 0, thisSave.inventoryItems.Length); foreach (Grid grid in inventoryGrid.Children.OfType <Grid>()) { foreach (ComboBox comboBox in grid.Children.OfType <ComboBox>()) { thisSave.inventoryItems[i] = IDs.GetID(comboBox.SelectedItem.ToString()); i++; } } i = 0; Array.Clear(thisSave.phoneItems, 0, thisSave.phoneItems.Length); foreach (var checkBox in phoneItemsGrid.Children.OfType <CheckBox>()) { if ((bool)checkBox.IsChecked) { thisSave.phoneItems[i] = IDs.GetID(checkBox.Content.ToString()); i++; } } thisSave.SaveName = saveNameBox.Text; thisINI = INI.GetINI(); thisINI.sansMetInJudgment = MiscFunctions.SetBooleanValueFromLocation(thisSave.Location, 232); if (thisSave.Location == 999) { thisINI.photoshopFight = true; } else { thisINI.skipFight = false; } if (thisSave.Location == 998) { thisSave = SAVE.SAVEFile.SetSaveForRoute(thisSave, thisSave.Location, Routes.GameRoutes.Genocide); genocideRadio.IsChecked = true; } if (GetSelectedRoute() >= Routes.GameRoutes.TruePacifistAsrielTalk) { thisINI.barrierDestroyed = true; } if (GetSelectedRoute() == Routes.GameRoutes.TruePacifistEpilogue) { thisINI.canTrueReset = true; } else if (GetSelectedRoute() == Routes.GameRoutes.Genocide) { thisINI.killedSans = MiscFunctions.SetBooleanValueFromLocation(thisSave.Location, 232); } }
//WriteSaveFile writes, well, the save file. public static bool WriteSaveFile(SAVEFile fileToWrite, INI.INIFile ini) { //SetFlagFromBool converts a boolean variable or value to a string to be written as a flag in file0 string SetFlagFromBool(bool booleanToCheck, int valueToSet = 1) { if (booleanToCheck) { return(valueToSet.ToString()); } else { return("0"); } } //We use an ordered dictionary with the key as the line number in file0 to write the value to OrderedDictionary file0Contents = new OrderedDictionary { { 1, fileToWrite.PlayerName }, { 2, fileToWrite.LOVE.ToString() }, { 3, fileToWrite.HP.ToString() }, { 4, "0" }, { 5, fileToWrite.friskAT.ToString() }, { 6, fileToWrite.weaponAT.ToString() }, { 7, fileToWrite.friskDF.ToString() }, { 8, fileToWrite.armorDF.ToString() }, { 9, "4" }, { 10, fileToWrite.EXP.ToString() }, { 11, fileToWrite.GOLD.ToString() }, { 12, fileToWrite.KillCount.ToString() }, { 13, fileToWrite.inventoryItems[0].ToString() }, { 14, fileToWrite.phoneItems[0].ToString() }, { 15, fileToWrite.inventoryItems[1].ToString() }, { 16, fileToWrite.phoneItems[1].ToString() }, { 17, fileToWrite.inventoryItems[2].ToString() }, { 18, fileToWrite.phoneItems[2].ToString() }, { 19, fileToWrite.inventoryItems[3].ToString() }, { 20, fileToWrite.phoneItems[3].ToString() }, { 21, fileToWrite.inventoryItems[4].ToString() }, { 22, "0" }, { 23, fileToWrite.inventoryItems[5].ToString() }, { 24, "0" }, { 25, fileToWrite.inventoryItems[6].ToString() }, { 26, "0" }, { 27, fileToWrite.inventoryItems[7].ToString() }, { 28, "0" }, { 29, fileToWrite.Weapon }, { 30, fileToWrite.Armor }, { 38, Convert.ToInt16(fileToWrite.asrielDefeated) }, { 39, Convert.ToInt16(fileToWrite.randomCountersDisabled) }, { 45, (int)fileToWrite.ruinsDummyState }, { 76, (int)fileToWrite.torielState }, { 83, (int)fileToWrite.doggoState }, { 84, (int)fileToWrite.dogamyState }, { 85, (int)fileToWrite.greaterDogState }, { 88, (int)fileToWrite.comedianState }, { 98, (int)fileToWrite.papyrusState }, { 112, (int)fileToWrite.shyrenState }, { 119, (int)fileToWrite.papyrusDated }, { 232, fileToWrite.KillCount }, { 233, fileToWrite.ruinsKills }, { 234, fileToWrite.snowdinKills }, { 235, fileToWrite.waterfallKills }, { 236, fileToWrite.hotlandKills }, { 282, (int)fileToWrite.undyneState }, { 283, (int)fileToWrite.madDummyState }, { 381, (int)fileToWrite.undyneState }, { 398, Convert.ToInt16(fileToWrite.disableAlphysCalls) }, { 399, Convert.ToInt16(fileToWrite.disableAlphysCalls) }, { 402, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 404, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 405, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 406, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 420, (int)fileToWrite.undyneDated }, { 428, (int)fileToWrite.muffetState }, { 430, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 431, Convert.ToInt16(fileToWrite.disableHotlandPuzzles) }, { 433, (int)fileToWrite.broGuardsState }, { 449, SetFlagFromBool(fileToWrite.coreElevatorUnlocked) }, { 456, (int)fileToWrite.mettatonState }, { 462, SetFlagFromBool(fileToWrite.insideCastle) }, { 463, SetFlagFromBool(fileToWrite.rodeCastleLift) }, { 481, SetFlagFromBool(ini.skipAsrielStory, 17) }, { 483, SetFlagFromBool(fileToWrite.unlockedCastleChain) }, { 484, SetFlagFromBool(fileToWrite.unlockedCastleChain) }, { 485, SetFlagFromBool(fileToWrite.unlockedCastleChain) }, { 486, SetFlagFromBool(ini.skipAsrielStory) }, { 487, SetFlagFromBool(ini.skipAsrielStory, 2) }, { 496, Convert.ToInt16(fileToWrite.undyneOnPhone) }, { 510, SetFlagFromBool(fileToWrite.asrielDefeated, 2) }, { 512, SetFlagFromBool(fileToWrite.beatTrueLab, 3) }, { 513, SetFlagFromBool(fileToWrite.beatTrueLab, 3) }, { 514, SetFlagFromBool(fileToWrite.beatTrueLab, 3) }, { 515, SetFlagFromBool(fileToWrite.beatTrueLab, 3) }, { 516, SetFlagFromBool(fileToWrite.beatTrueLab) }, { 517, SetFlagFromBool(fileToWrite.beatTrueLab, 10) }, { 518, SetFlagFromBool(fileToWrite.beatTrueLab, 0) }, { 519, SetFlagFromBool(fileToWrite.beatTrueLab) }, { 520, SetFlagFromBool(fileToWrite.beatTrueLab) }, { 521, SetFlagFromBool(fileToWrite.beatTrueLab) }, { 522, SetFlagFromBool(fileToWrite.beatTrueLab) }, { 523, SetFlagFromBool(fileToWrite.dateAlphysFlag) }, { 524, fileToWrite.pacifistStage }, { 543, fileToWrite.Plot }, { 544, "1" }, { 545, "1" }, { 546, SetFlagFromBool(MiscFunctions.SetBooleanValueFromLocation(fileToWrite.Location, 12)) }, //Cell Phone { 547, "0" }, { 548, fileToWrite.Location.ToString() }, { 549, "0" } }; if (fileToWrite.Location == 998) { fileToWrite.Location = 235; FileOperations.setGenocide(GenocideStates.Abyss); } else if (fileToWrite.Location == 999) { fileToWrite.Location = 237; } try { StreamWriter file0Writer = new StreamWriter(File.Open(Constants.SavesPath + fileToWrite.SaveName + "//file0", FileMode.Create), Encoding.ASCII); //We iterate through every line and key in file0Contents and if the key value matches lineNumber, we write the corresponding value for (int lineNumber = 1; lineNumber <= 549; lineNumber++) { foreach (DictionaryEntry file0Entry in file0Contents) { if ((int)file0Entry.Key == lineNumber) { file0Writer.WriteLine(file0Entry.Value.ToString()); break; } else if ((int)file0Entry.Key > lineNumber) { file0Writer.WriteLine("0"); break; } } } file0Writer.Close(); if (fileToWrite.Location >= 238 || fileToWrite.Plot >= 208) { File.Copy(Constants.SavesPath + fileToWrite.SaveName + "//file0", Constants.SavesPath + fileToWrite.SaveName + "//file8", true); } return(true); } catch (Exception ex) { System.Windows.MessageBox.Show("An exception occurred when writing the save file. Cannot continue. The exception was: \n\n" + ex, "Error!", MessageBoxButton.OK, MessageBoxImage.Error); return(false); } }