2025-05-13 19:22:01 +08:00

525 lines
13 KiB
C#

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<AudioStream>("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<SaveFile>(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<string> list = new List<string>();
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<PackedScene>("res://Objects/UI/GenericList.tscn").Instantiate<GenericList>(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<PackedScene>("res://Objects/UI/Settings.tscn").Instantiate<Settings>(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<PackedScene>("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<PackedScene>("res://Objects/Characters/Clover.tscn").Instantiate<Entity>(PackedScene.GenEditState.Disabled), forceReadableName: false, InternalMode.Disabled);
Common.SwapType<Entity, Player>(ref en, "Entities/");
en._EnterTree();
return en;
}
}