using System.Collections; using System.Collections.Generic; using System.ComponentModel; using Godot; using Godot.Bridge; using Godot.NativeInterop; using Newtonsoft.Json; [ScriptPath("res://Scripts/UI/MainMenu.cs")] public partial class MainMenu : Control { [Export(PropertyHint.None, "")] private NinePatchRect[] files; [Export(PropertyHint.None, "")] private RichTextLabel[] fileText; [Export(PropertyHint.None, "")] private RichTextLabel[] opt; [Export(PropertyHint.None, "")] private NinePatchRect settingsBox; [Export(PropertyHint.None, "")] private RichTextLabel top; [Export(PropertyHint.None, "")] private Sprite2D soul; [Export(PropertyHint.None, "")] private Sprite2D logo; [Export(PropertyHint.None, "")] private Control fileMenu; private string[][] langs; public int option; public int maxOption = 6; public int current; public int subOption; public int copySlot = -1; public int file; private float sec; private static SaveFile[] saves = new SaveFile[3]; private static bool firstLoad; public static string lastLang = null; public static MainMenu instance; public static int forceReload = -1; private Settings settings; private Coroutine delay; private GenericList langList; private AudioStreamPlayer introsound; private static readonly AudioStream music = GD.Load("res://Audio/Music/AUDIO_STORY.ogg"); private static readonly Vector2[] optPos = new Vector2[6] { new Vector2(-124f, -65f), new Vector2(-124f, -4f), new Vector2(-124f, 57f), new Vector2(-102f, 98f), new Vector2(-30f, 98f), new Vector2(42f, 98f) }; private string[] mes; private static readonly StringName intronoise = "AUDIO_INTRONOISE.ogg"; public override void _EnterTree() { if (instance == null) { instance = this; } base.Visible = true; if (saves == null) { saves = new SaveFile[3]; } if (lastLang != null) { Settings.file.lang = lastLang; } SetMes(); for (int i = 0; i < saves.Length; i++) { if (FileAccess.FileExists("user://Save" + i + ".dat")) { using FileAccess fileAccess = FileAccess.Open("user://Save" + i + ".dat", FileAccess.ModeFlags.Read); saves[i] = JsonConvert.DeserializeObject(fileAccess.GetAsText()); fileAccess.Close(); files[i].Modulate = Main.colorWhite; } else { saves[i] = null; } SetFileText(in i); } if (forceReload > -1) { base.Modulate = Main.colorClear; current = -1; Coroutine.Start(LoadFile(forceReload, skip: true)); forceReload = -1; return; } if (current != -1 && !firstLoad && DirAccess.DirExistsAbsolute("user://Text/")) { string[] directoriesAt = DirAccess.GetDirectoriesAt("user://Text/"); if (directoriesAt.Length != 0) { List list = new List(); langs = new string[directoriesAt.Length + 1][]; langs[0] = FileAccess.Open("res://Data/Text_EnUS/LangInfo.txt", FileAccess.ModeFlags.Read).GetAsText().Split('\n'); langs[0][2] = "EnUS"; list.Add(langs[0][1]); for (int j = 1; j < langs.Length; j++) { langs[j] = FileAccess.Open("user://Text/" + directoriesAt[j - 1] + "/LangInfo.txt", FileAccess.ModeFlags.Read).GetAsText().Split('\n'); langs[j][2] = directoriesAt[j - 1].Split('_', 2)[1]; list.Add(langs[j][1]); } current = -2; AddChild(langList = GD.Load("res://Objects/UI/GenericList.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); langList.options = list.ToArray(); langList.Scrolled += UpdateLangHeader; langList.Selected += LangSelected; langList.Position = new Vector2(-74f, -70f); UpdateLangHeader(); logo.ProcessMode = ProcessModeEnum.Disabled; } } if (current != -2 && current <= 0) { introsound = Audio.PlaySound(intronoise); } firstLoad = true; } private void SetFileText(in int i) { if (saves[i] != null) { fileText[i].Text = "[center]" + Texts.common[28].ToUpper() + "\t\t\t\t" + Texts.common[91] + " " + saves[i].love + "\t\t\t\t" + Texts.common[92] + " " + saves[i].lv + "\n" + SaveFile.GetRoomName(saves[i].room) + "\n" + saves[i].time[2].ToString().PadLeft(3, '0') + ":" + saves[i].time[1].ToString().PadLeft(2, '0'); } else { fileText[i].Text = "\n[center]" + Texts.common[89]; } } private void SetMes() { mes = new string[9] { "[center]" + Texts.common[77], "\t\t" + Texts.common[78], "", "[center]" + Texts.common[78], "\t\t" + Texts.common[79] + "\t\t\t\t[color=#202020]" + Texts.common[80] + "\t\t\t\t" + Texts.common[81], "[center]" + Texts.common[82], "[center][color=red]" + Texts.common[83], "", "[center]" + Texts.common[86] }; } private void UpdateLangHeader() { langList.label.Text = "[center]" + langs[langList.current][0]; } private void LangSelected() { Settings.file.lang = langs[langList.current][2]; Texts.LoadText(); SetMes(); _Ready(); lastLang = Settings.file.lang; for (int i = 0; i < saves.Length; i++) { SetFileText(in i); } langList.QueueFree(); } public override void _Ready() { opt[0].Text = mes[1]; opt[1].Text = ""; opt[2].Text = ""; top.Text = mes[0]; } private void SetOpt() { opt[0].Text = "\t\t" + Texts.common[79]; opt[1].Text = ((saves[file] == null) ? "[color=#202020]" : "") + "\t\t" + Texts.common[80]; opt[2].Text = ((saves[file] == null) ? "[color=#202020]" : "") + "\t\t" + Texts.common[81]; } public override void _Process(double delta) { if (delay != null) { return; } switch (current) { case -2: if (!GodotObject.IsInstanceValid(langList)) { introsound = Audio.PlaySound(intronoise); current = 0; logo.ProcessMode = ProcessModeEnum.Inherit; } break; case -1: base.Modulate = base.Modulate.Lerp(Main.colorClear, 0.1f * Main.deltaTime); break; case 0: if (sec < 630f) { sec += Main.deltaTime; if (Input.IsActionJustPressed(Main.keys[4])) { current = 1; sec = 0f; Audio.FadeSound(introsound, 2f); } } else { current = 2; } break; case 1: if (sec < 60f) { sec += Main.deltaTime; logo.Modulate = Main.colorWhite.Lerp(Main.colorClear, sec / 60f); } else { current = 2; } break; case 2: if (!Audio.music.Playing) { Audio.ChangeMusic(music); } soul.Position = optPos[option]; fileMenu.Modulate = fileMenu.Modulate.Lerp(Main.colorWhite, 0.1f * Main.deltaTime); if (Input.IsActionJustPressed(Main.keys[0]) || Input.IsActionJustPressed(Main.keys[2])) { option = (int)Main.Repeat(option - 1, (subOption == 0) ? 4 : 3); Audio.PlaySound(Audio.commonSounds[0]); } else if (Input.IsActionJustPressed(Main.keys[1]) || Input.IsActionJustPressed(Main.keys[3])) { option = (int)Main.Repeat(option + 1, (subOption == 0) ? 4 : 3); Audio.PlaySound(Audio.commonSounds[0]); } else if (Input.IsActionJustPressed(Main.keys[4])) { if (option != 3) { if (subOption == 0) { Audio.PlaySound(Audio.commonSounds[2]); file = option; option = 0; current = 4; SetOpt(); top.Text = "[center]" + Texts.common[87].Replace("@", (file + 1).ToString()); } else if (file == option) { Audio.PlaySound(Audio.commonSounds[1]); } else { FileCopy(); Audio.PlaySound(Audio.commonSounds[2]); } } else { Audio.PlaySound(Audio.commonSounds[2]); fileMenu.Visible = false; settingsBox.AddChild(settings = GD.Load("res://Objects/UI/Settings.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); settings.Position = new Vector2(27f, 14f); current = 3; settingsBox.Visible = true; } } else if (Input.IsActionJustPressed(Main.keys[5]) && subOption > 0) { Cancel(); } break; case 3: if (!GodotObject.IsInstanceValid(settings)) { settings = null; current = 2; settingsBox.Visible = false; fileMenu.Visible = true; } break; case 4: soul.Position = optPos[3 + option]; if (Input.IsActionJustPressed(Main.keys[0]) || Input.IsActionJustPressed(Main.keys[2])) { option = (int)Main.Repeat(option - 1, (subOption == 0) ? 3 : 2); Audio.PlaySound(Audio.commonSounds[0]); } else if (Input.IsActionJustPressed(Main.keys[1]) || Input.IsActionJustPressed(Main.keys[3])) { option = (int)Main.Repeat(option + 1, (subOption == 0) ? 3 : 2); Audio.PlaySound(Audio.commonSounds[0]); } else if (Input.IsActionJustPressed(Main.keys[4])) { if (subOption == 1) { if (option == 0) { subOption = 0; opt[0].Text = "\t\t" + Texts.common[79]; opt[1].Text = "\t\t" + Texts.common[80]; opt[2].Text = "\t\t" + Texts.common[81]; top.Text = mes[0]; option = 2; } else { FileDelete(); } Audio.PlaySound(Audio.commonSounds[2]); } else { if (subOption != 0) { break; } if (saves[file] == null && option != 0) { Audio.PlaySound(Audio.commonSounds[1]); break; } Audio.PlaySound(Audio.commonSounds[2]); switch (option) { case 0: Main.inEvent = Coroutine.Start(LoadFile(file)); current = -1; break; case 1: subOption = 2; top.Text = mes[5]; opt[0].Text = ""; opt[1].Text = ""; opt[2].Text = ""; option = file; current = 2; files[file].Modulate = Main.colorYellow; break; case 2: subOption = 1; opt[0].Text = "\t\t" + Texts.common[84]; opt[1].Text = "\t\t[color=red]" + Texts.common[85]; opt[2].Text = ""; top.Text = mes[6]; option = 0; break; } } } else if (Input.IsActionJustPressed(Main.keys[5])) { Cancel(); } break; case 5: break; } } private void Cancel() { subOption = 0; current = 2; option = file; _Ready(); for (int i = 0; i < files.Length; i++) { files[i].Modulate = Main.colorWhite; } } private void FileCopy() { using FileAccess fileAccess = FileAccess.Open("user://Save" + option + ".dat", FileAccess.ModeFlags.Write); fileAccess.StoreString(JsonConvert.SerializeObject(saves[file])); fileAccess.Close(); Cancel(); _EnterTree(); top.Text = mes[8]; } private void FileDelete() { Error error = DirAccess.RemoveAbsolute("user://Save" + file + ".dat"); saves = null; current = 2; option = file; subOption = 0; _Ready(); _EnterTree(); if (error == Error.Ok) { Audio.PlaySound("AUDIO_APPEARANCE.wav"); } else { Audio.PlaySound("snd_error.wav"); } top.Text = ((error == Error.Ok) ? mes[8] : ("[center][color=red]" + Texts.common[88])); delay = null; } public static IEnumerator LoadFile(int id, bool skip = false) { Audio.ChangeMusic(null); if (!skip) { for (float a = 0f; a < 30f; a += Main.deltaTime) { instance.Modulate = Main.colorWhite.Lerp(Main.colorClear, a / 30f); yield return null; } for (float a = 0f; a < 30f; a += Main.deltaTime) { yield return null; } } instance.QueueFree(); instance = null; if (saves[id] == null) { SaveFile.current.time = new int[3]; CameraController.instance.AddChild(GD.Load("res://Objects/Events/Intro.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); } else { SaveFile.current = saves[id]; SaveFile.current.LoadStats(); if (SaveFile.HasFlag(SaveFile.Flags.JuneRecessDay2)) { SaveFile.AddFlag(SaveFile.Flags.SchoolRecessDay2); } CameraController.Transition(Main.colorBlack); yield return null; Room.LoadRoom(SaveFile.current.room); yield return null; SetPlayer(); yield return null; Player.instance.GlobalPosition = SaveFile.current.position; CameraController.instance.GlobalPosition = Player.instance.GlobalPosition + CameraController.instance.offset; Player.instance.UpdateAnim(force: true); yield return null; Player.instance.FollowerSetUp(); CameraController.Transition(Main.colorClearB, 30f); Room.current.DoMusic(); yield return null; Room.SpawnFollowers(); Player.instance.GetParent().MoveChild(Player.instance, Player.instance.GetParent().GetChildCount() - 1); yield return null; while (true) { Coroutine transitionRoutine = CameraController.transitionRoutine; if (transitionRoutine == null || transitionRoutine.done) { break; } yield return null; } Player.instance.canInput = true; Party.UpdateStats(); } SaveFile.current.slot = id; } public static Entity SetPlayer() { Entity en; Room.current.AddChild(en = GD.Load("res://Objects/Characters/Clover.tscn").Instantiate(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled); Common.SwapType(ref en, "Entities/"); en._EnterTree(); return en; } }