diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj
index 1bbbf50e..614a2046 100644
--- a/Assembly-CSharp.csproj
+++ b/Assembly-CSharp.csproj
@@ -239,6 +239,7 @@
+
@@ -254,6 +255,7 @@
+
diff --git a/Assets.Scripts.Core.AssetManagement/AssetManager.cs b/Assets.Scripts.Core.AssetManagement/AssetManager.cs
index ce36426d..95599dc3 100644
--- a/Assets.Scripts.Core.AssetManagement/AssetManager.cs
+++ b/Assets.Scripts.Core.AssetManagement/AssetManager.cs
@@ -117,8 +117,8 @@ public string PathToAssetWithName(string name, PathCascadeList artset)
{
int backgroundSetIndex = BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue();
- // If force og backgrounds is enabled, always check OGBackgrounds first.
- if (backgroundSetIndex == 2)
+ // If OG backgrounds are enabled, always check OGBackgrounds first.
+ if (backgroundSetIndex == 1)
{
string filePath = Path.Combine(Path.Combine(assetPath, "OGBackgrounds"), name);
if (File.Exists(filePath))
@@ -129,8 +129,8 @@ public string PathToAssetWithName(string name, PathCascadeList artset)
foreach (var artSetPath in artset.paths)
{
- // If force console backgrounds is enabled, don't check OGBackgrounds
- if (backgroundSetIndex == 1 && artSetPath == "OGBackgrounds")
+ // If console backgrounds are enabled, don't check OGBackgrounds
+ if (backgroundSetIndex == 0 && artSetPath == "OGBackgrounds")
{
continue;
}
diff --git a/Assets.Scripts.Core.Buriko/BurikoMemory.cs b/Assets.Scripts.Core.Buriko/BurikoMemory.cs
index 40834fd6..70dc317e 100644
--- a/Assets.Scripts.Core.Buriko/BurikoMemory.cs
+++ b/Assets.Scripts.Core.Buriko/BurikoMemory.cs
@@ -3,6 +3,7 @@
using Assets.Scripts.Core.Buriko.VarTypes;
using MOD.Scripts.Core.Audio;
using MOD.Scripts.Core.Scene;
+using MOD.Scripts.UI;
using Newtonsoft.Json;
using Newtonsoft.Json.Bson;
using System;
@@ -29,6 +30,8 @@ internal class BurikoMemory
private List cgflags = new List();
+ private MODCustomFlagPreset customFlagPreset = new MODCustomFlagPreset();
+
private int scopeLevel;
public static BurikoMemory Instance
@@ -187,6 +190,11 @@ public void ResetScope()
MODSceneController.ClearLayerFilters();
}
+ public MODCustomFlagPreset GetCustomFlagPresetInstance()
+ {
+ return customFlagPreset;
+ }
+
public bool SeenCG(string cg)
{
return cgflags.Contains(cg);
@@ -527,6 +535,25 @@ public void LoadGlobals()
{
readText = jsonSerializer.Deserialize>>(reader);
}
+ try
+ {
+ using (BsonReader reader = new BsonReader(stream) { CloseInput = false })
+ {
+ Dictionary deserializedState = jsonSerializer.Deserialize>(reader);
+ if(deserializedState == null)
+ {
+ Debug.LogWarning("Failed to load graphics preset state (serializer returned null)! Probably is old global.dat file missing this data.");
+ }
+ else
+ {
+ customFlagPreset.Flags = deserializedState;
+ }
+ }
+ }
+ catch(Exception arg)
+ {
+ Debug.LogWarning("Failed to load graphics preset state! Exception: " + arg);
+ }
}
}
catch (Exception arg)
@@ -574,6 +601,11 @@ public void SaveGlobals()
jsonSerializer.Serialize(jsonWriter, globalFlags);
jsonSerializer.Serialize(jsonWriter, cgflags);
jsonSerializer.Serialize(jsonWriter, readText);
+ if(customFlagPreset.Enabled)
+ {
+ customFlagPreset.SavePresetToMemory();
+ }
+ jsonSerializer.Serialize(jsonWriter, customFlagPreset.Flags);
inputBytes = memoryStream.ToArray();
}
}
diff --git a/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs b/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs
index 6affea92..0c75ee2b 100644
--- a/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs
+++ b/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs
@@ -2508,6 +2508,9 @@ public BurikoVariable OperationMODDrawCharacter()
bool flag = ReadVariable().BoolValue();
string textureName2 = textureName + "0";
string text = textureName + str;
+
+ x = MODRyukishiRevertSpritePosition(textureName, x);
+
MODSystem.instance.modSceneController.MODLipSyncInvalidateAndGenerateId(character);
if (!MODSystem.instance.modSceneController.MODLipSyncIsEnabled())
{
@@ -2556,6 +2559,9 @@ public BurikoVariable OperationMODDrawCharacterWithFiltering()
bool flag = ReadVariable().BoolValue();
string textureName2 = textureName + "0";
string text = textureName + str;
+
+ x = MODRyukishiRevertSpritePosition(textureName, x);
+
MODSystem.instance.modSceneController.MODLipSyncInvalidateAndGenerateId(character);
if (!MODSystem.instance.modSceneController.MODLipSyncIsEnabled())
{
@@ -2769,7 +2775,7 @@ public BurikoVariable OperationMODGenericCall()
case "ShowSetupMenuIfRequired":
if(MODAudioSet.Instance.HasAudioSetsDefined() && !MODAudioSet.Instance.GetCurrentAudioSet(out _))
{
- GameSystem.Instance.MainUIController.modMenu.SetMode(ModMenuMode.AudioSetup);
+ GameSystem.Instance.MainUIController.modMenu.SetSubMenu(ModSubMenu.AudioSetup);
GameSystem.Instance.MainUIController.modMenu.Show();
}
break;
@@ -2780,5 +2786,35 @@ public BurikoVariable OperationMODGenericCall()
}
return BurikoVariable.Null;
}
+
+ ///
+ /// This function reverts the x positions of sprites when using 4:3 backgrounds to match the original game
+ /// In some places, our mod has 'spread out' the sprite positions to better match 16:9 widescreen by setting
+ /// their X position to 240/-240 instead of 160/-160 (mostly when there are 3 characters on the screen at once).
+ /// However, when playing in 4:3 mode, this causes the sprites to be more cut-off than they were in the original game.
+ /// This function attempts to revert this specific case by changing an X of 240/-240 into 160/-160.
+ ///
+ private int MODRyukishiRevertSpritePosition(string path, int x)
+ {
+ path = path.ToLower();
+
+ if(BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() == 1 && // Using OG Backgrounds AND
+ BurikoMemory.Instance.GetGlobalFlag("GStretchBackgrounds").IntValue() == 0) // Not stretching backgrounds
+ {
+ if (path.StartsWith("sprite/") || path.StartsWith("portrait/")) // is from the sprite or portrait folder
+ {
+ if (x == 240)
+ {
+ return 160;
+ }
+ else if (x == -240)
+ {
+ return -160;
+ }
+ }
+ }
+
+ return x;
+ }
}
}
diff --git a/Assets.Scripts.Core.Scene/Layer.cs b/Assets.Scripts.Core.Scene/Layer.cs
index 7fb2d00b..cea1b841 100644
--- a/Assets.Scripts.Core.Scene/Layer.cs
+++ b/Assets.Scripts.Core.Scene/Layer.cs
@@ -334,7 +334,15 @@ private void EnsureCorrectlySizedMesh(int width, int height, LayerAlignment alig
bool stretchToFit = false;
if (texturePath != null)
{
- ryukishiClamp = isBustShot && Buriko.BurikoMemory.Instance.GetGlobalFlag("GRyukishiMode").IntValue() == 1 && (texturePath.Contains("sprite/") || texturePath.Contains("sprite\\"));
+ // We want to clamp sprites to 4:3 if you are using the OG backgrounds, and you are not stretching the background
+ ryukishiClamp = isBustShot &&
+ Buriko.BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() == 1 && // Using OG Backgrounds AND
+ Buriko.BurikoMemory.Instance.GetGlobalFlag("GStretchBackgrounds").IntValue() == 0 && // Not stretching backgrounds AND
+ (texturePath.Contains("sprite/") ||
+ texturePath.Contains("sprite\\") ||
+ texturePath.Contains("portrait/") ||
+ texturePath.Contains("portrait\\")); // Is a sprite or portrait image. I don't think we can rely only on isBustShot, as sometimes non-sprites are drawn with isBustShot
+
stretchToFit = Buriko.BurikoMemory.Instance.GetGlobalFlag("GStretchBackgrounds").IntValue() == 1 && texturePath.Contains("OGBackgrounds");
}
@@ -816,72 +824,5 @@ private void Update()
public void MODOnlyRecompile()
{
}
-
- public void MODDrawLayer(string textureName, Texture2D tex2d, int x, int y, int z, Vector2? origin, float alpha, bool isBustshot, int type, float wait, bool isBlocking)
- {
- cachedIsBustShot = isBustshot;
- FinishAll();
- if (textureName == string.Empty)
- {
- HideLayer();
- }
- else if (tex2d == null)
- {
- Logger.LogError("Failed to load texture " + textureName);
- }
- else
- {
- startRange = 0f;
- targetRange = alpha;
- targetAlpha = alpha;
- meshRenderer.enabled = true;
- shaderType = type;
- PrimaryName = textureName;
- float num = 1f;
- if (z > 0)
- {
- num = 1f - (float)z / 400f;
- }
- if (z < 0)
- {
- num = 1f + (float)z / -400f;
- }
- EnsureCorrectlySizedMesh(
- width: tex2d.width, height: tex2d.height,
- alignment: ((x != 0 || y != 0) && !isBustshot) ? LayerAlignment.AlignTopleft : LayerAlignment.AlignCenter,
- origin: origin,
- isBustShot: isBustshot,
- finalXOffset: x,
- texturePath: null
- );
- if (primary != null)
- {
- material.shader = shaderCrossfade;
- SetSecondaryTexture(primary);
- SetPrimaryTexture(tex2d);
- startRange = 1f;
- targetRange = 0f;
- targetAlpha = 1f;
- }
- else
- {
- material.shader = shaderDefault;
- if (type == 3)
- {
- material.shader = shaderMultiply;
- }
- SetPrimaryTexture(tex2d);
- }
- SetRange(startRange);
- base.transform.localPosition = new Vector3((float)x, 0f - (float)y, (float)Priority * -0.1f);
- base.transform.localScale = new Vector3(num, num, 1f);
- targetPosition = base.transform.localPosition;
- targetScale = base.transform.localScale;
- if (Mathf.Approximately(wait, 0f))
- {
- FinishFade();
- }
- }
- }
}
}
diff --git a/Assets.Scripts.Core.Scene/SceneController.cs b/Assets.Scripts.Core.Scene/SceneController.cs
index c4ff0424..c6d23dcd 100644
--- a/Assets.Scripts.Core.Scene/SceneController.cs
+++ b/Assets.Scripts.Core.Scene/SceneController.cs
@@ -767,6 +767,14 @@ public void ReloadAllImages()
{
layer.ReloadTexture();
}
+
+ // Force Unity to unload unused assets.
+ // Higuarshi will do this if you play the game normally each time ExecuteActions()
+ // is called (it appears as "Unloading 7 unused Assets to reduce memory usage." in the log).
+ // However, if you don't advance the text, it won't ever clean up.
+ // Eventually, you can run out of memory if this function is repeatedly
+ // called (for example, constantly toggling art styles)
+ Resources.UnloadUnusedAssets();
}
private Scene GetActiveScene()
@@ -839,54 +847,6 @@ public void MODOnlyRecompile()
{
}
- public void MODDrawBustshot(int layer, string textureName, Texture2D tex2d, int x, int y, int z, int oldx, int oldy, int oldz, bool move, int priority, int type, float wait, bool isblocking)
- {
- if (MODSkipImage(textureName))
- {
- return;
- }
-
- Layer layer2 = GetLayer(layer);
- while (layer2.FadingOut)
- {
- layer2.HideLayer();
- layer2 = GetLayer(layer);
- }
- if (!move)
- {
- oldx = x;
- oldy = y;
- oldz = z;
- }
- layer2.MODDrawLayer(textureName, tex2d, oldx, oldy, oldz, null, 1f, /*isBustshot:*/ true, type, wait, isblocking);
- layer2.SetPriority(priority);
- if (move)
- {
- layer2.MoveLayer(x, y, z, 1f, 0, wait, isblocking, adjustAlpha: false);
- }
- iTween.Stop(layer2.gameObject);
- if (Mathf.Approximately(wait, 0f))
- {
- layer2.FinishFade();
- }
- else
- {
- layer2.FadeInLayer(wait);
- if (isblocking)
- {
- GameSystem.Instance.AddWait(new Wait(wait, WaitTypes.WaitForMove, layer2.FinishFade));
- }
- if (layer2.UsingCrossShader() && layer2.gameObject.layer != GetActiveLayerMask())
- {
- SetLayerActiveOnBothScenes(layer2);
- }
- else
- {
- UpdateLayerMask(layer2, priority);
- }
- }
- }
-
public IEnumerator MODDrawLipSync(int character, int audiolayer, string audiofile)
{
ulong coroutineId = MODSystem.instance.modSceneController.MODLipSyncInvalidateAndGenerateId(character);
@@ -916,13 +876,13 @@ public IEnumerator MODDrawLipSync(int character, int audiolayer, string audiofil
switch (exparray[k])
{
case "2":
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "2", exp2, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp2, coroutineId);
break;
case "1":
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "1", exp3, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp3, coroutineId);
break;
case "0":
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "0", exp4, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp4, coroutineId);
break;
}
}
@@ -931,9 +891,9 @@ public IEnumerator MODDrawLipSync(int character, int audiolayer, string audiofil
}
else
{
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "0", exp4, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp4, coroutineId);
yield return (object)new WaitForSeconds(0.25f);
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "1", exp3, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp3, coroutineId);
yield return (object)new WaitForSeconds(0.25f);
int k = 0;
if (GameSystem.Instance.AudioController.IsVoicePlaying(audiolayer))
@@ -948,14 +908,14 @@ public IEnumerator MODDrawLipSync(int character, int audiolayer, string audiofil
{
break;
}
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "0", exp4, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp4, coroutineId);
yield return (object)new WaitForSeconds(0.25f);
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "1", exp3, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp3, coroutineId);
yield return (object)new WaitForSeconds(0.25f);
}
}
}
- MODSystem.instance.modSceneController.MODLipSyncProcess(character, "0", exp4, coroutineId);
+ MODSystem.instance.modSceneController.MODLipSyncProcess(character, exp4, coroutineId);
}
public void MODLipSyncStart(int character, int audiolayer, string audiofile)
diff --git a/Assets.Scripts.UI/MainUIController.cs b/Assets.Scripts.UI/MainUIController.cs
index 56d14f90..1cfe0a2a 100644
--- a/Assets.Scripts.UI/MainUIController.cs
+++ b/Assets.Scripts.UI/MainUIController.cs
@@ -520,7 +520,7 @@ public void OnGUI()
{
if(BurikoSaveManager.lastSaveError != null)
{
- MODMenuSupport.EmergencyModMenu("Error loading save file! Please backup your saves, DISABLE STEAM SYNC, then delete the following save file:", BurikoSaveManager.lastSaveError);
+ MODMenuSupport.EmergencyModMenu("Error loading save file! Please 1. Backup your saves, 2. DISABLE STEAM CLOUD, 3. Delete the following save file:", BurikoSaveManager.lastSaveError);
return;
}
diff --git a/MOD.Scripts.Core.Scene/MODSceneController.cs b/MOD.Scripts.Core.Scene/MODSceneController.cs
index b4ed7655..1fdd9828 100644
--- a/MOD.Scripts.Core.Scene/MODSceneController.cs
+++ b/MOD.Scripts.Core.Scene/MODSceneController.cs
@@ -347,18 +347,12 @@ public bool MODLipSyncIsAnimationCurrent(int character, ulong coroutineId)
return coroutineId == MODLipSync_CoroutineId[character];
}
- public void MODLipSyncProcess(int charnum, string expressionnum, Texture2D tex2d, ulong coroutineId)
+ public void MODLipSyncProcess(int charnum, Texture2D tex2d, ulong coroutineId)
{
if (MODLipSyncIsAnimationCurrent(charnum, coroutineId))
{
int layer = MODLipSync_Layer[charnum];
- string textureName = MODLipSync_Texture[charnum] + expressionnum;
- int x = MODLipSync_X[charnum];
- int y = MODLipSync_Y[charnum];
- int z = MODLipSync_Z[charnum];
- int priority = MODLipSync_Priority[charnum];
- int type = MODLipSync_Type[charnum];
- GameSystem.Instance.SceneController.MODDrawBustshot(layer, textureName, tex2d, x, y, z, 0, 0, 0, /*move:*/ false, priority, type, 0f, /*isblocking:*/ false);
+ GameSystem.Instance.SceneController.GetLayer(layer)?.SetPrimaryTexture(tex2d);
}
}
}
diff --git a/MOD.Scripts.Core.Scene/MODTextureController.cs b/MOD.Scripts.Core.Scene/MODTextureController.cs
index 4fdc5e14..24ed892f 100644
--- a/MOD.Scripts.Core.Scene/MODTextureController.cs
+++ b/MOD.Scripts.Core.Scene/MODTextureController.cs
@@ -62,7 +62,6 @@ public void SetArtStyle(int artSetIndex, bool showInfoToast = true)
{
AssetManager.Instance.CurrentArtsetIndex = artSetIndex;
BurikoMemory.Instance.SetGlobalFlag("GArtStyle", AssetManager.Instance.CurrentArtsetIndex);
- BurikoMemory.Instance.SetGlobalFlag("GBackgroundSet", 0);
RestoreTextures();
GameSystem.Instance.SceneController.ReloadAllImages();
if (showInfoToast) { UI.MODToaster.Show($"Art Style: {AssetManager.Instance.CurrentArtset.nameEN}"); }
diff --git a/MOD.Scripts.UI/MODActions.cs b/MOD.Scripts.UI/MODActions.cs
index 55b45f36..74024134 100644
--- a/MOD.Scripts.UI/MODActions.cs
+++ b/MOD.Scripts.UI/MODActions.cs
@@ -22,8 +22,8 @@ private enum WindowFilterType
public enum ModPreset
{
- ADV = 0,
- NVL = 1,
+ Console = 0,
+ MangaGamer = 1,
OG = 2,
}
@@ -47,29 +47,36 @@ private static void TryRedrawTextWindowBackground(WindowFilterType filterType)
}
///
- /// Cycles and saves ADV->NVL->OG->ADV...
+ /// Cycles and saves Console->MangaGamer->OG->Custom->Console...
///
/// True if set and displayed, false if in a NVL_in_ADV region and value might not be applied immediately
public static void ToggleAndSaveADVMode()
{
- if (BurikoMemory.Instance.GetGlobalFlag("GRyukishiMode").IntValue() == 1)
- {
- SetAndSaveADV(ModPreset.ADV);
- }
- else if (BurikoMemory.Instance.GetGlobalFlag("GADVMode").IntValue() == 1)
+ MODCustomFlagPreset customPreset = BurikoMemory.Instance.GetCustomFlagPresetInstance();
+
+ // Custom Preset -> Console
+ if (customPreset.Enabled)
{
- SetAndSaveADV(ModPreset.NVL);
+ SetGraphicsPreset(ModPreset.Console);
+ return;
}
- else
+
+ switch (GetADVNVLRyukishiModeFromFlags())
{
- if(HasOGBackgrounds())
- {
- SetAndSaveADV(ModPreset.OG);
- }
- else
- {
- SetAndSaveADV(ModPreset.ADV);
- }
+ // Console -> MangaGamer
+ case 0:
+ SetGraphicsPreset(ModPreset.MangaGamer);
+ break;
+
+ // MangaGamer -> OG
+ case 1:
+ SetGraphicsPreset(ModPreset.OG);
+ break;
+
+ // OG -> Custom Preset
+ case 2:
+ LoadCustomGraphicsPreset();
+ break;
}
}
@@ -82,22 +89,80 @@ public static void ToggleAndSaveADVMode()
/// True if set and displayed, false if in a NVL_in_ADV region and value might not be applied immediately
///
/// NOTE: if this function is updated, you should update the corresponding "GetModeFromFlags()" function immediately below
- public static void SetAndSaveADV(ModPreset setting, bool showInfoToast = true)
+ public static void SetGraphicsPreset(ModPreset setting, bool showInfoToast = true)
{
MODMainUIController mODMainUIController = new MODMainUIController();
- if (setting == ModPreset.ADV)
+
+ BurikoMemory.Instance.GetCustomFlagPresetInstance().DisablePresetAndSavePresetToMemory();
+ if (setting == ModPreset.Console)
{
- BurikoMemory.Instance.SetGlobalFlag("GADVMode", 1);
- BurikoMemory.Instance.SetGlobalFlag("GLinemodeSp", 0);
- BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 0);
+ // Make sure lipsync is enabled when using Console preset
+ BurikoMemory.Instance.SetGlobalFlag("GLipSync", 1);
BurikoMemory.Instance.SetGlobalFlag("GHideCG", 0);
+ BurikoMemory.Instance.SetGlobalFlag("GBackgroundSet", 0);
+ BurikoMemory.Instance.SetGlobalFlag("GStretchBackgrounds", 0);
+ SetTextWindowAppearanceInternal(setting, mODMainUIController, false);
+ Core.MODSystem.instance.modTextureController.SetArtStyle(0, false);
+ if (showInfoToast) { UI.MODToaster.Show($"Preset: Console"); }
+ }
+ else if (setting == ModPreset.MangaGamer)
+ {
+ BurikoMemory.Instance.SetGlobalFlag("GHideCG", 0);
+ BurikoMemory.Instance.SetGlobalFlag("GBackgroundSet", 0);
+ BurikoMemory.Instance.SetGlobalFlag("GStretchBackgrounds", 0);
+ SetTextWindowAppearanceInternal(setting, mODMainUIController, false);
+ Core.MODSystem.instance.modTextureController.SetArtStyle(1, false);
+ if (showInfoToast) { UI.MODToaster.Show($"Preset: MangaGamer"); }
+ }
+ else if (setting == ModPreset.OG)
+ {
+ BurikoMemory.Instance.SetGlobalFlag("GHideCG", 1);
+ BurikoMemory.Instance.SetGlobalFlag("GBackgroundSet", 1);
BurikoMemory.Instance.SetGlobalFlag("GStretchBackgrounds", 0);
+ SetTextWindowAppearanceInternal(setting, mODMainUIController, false);
+ Core.MODSystem.instance.modTextureController.SetArtStyle(2, false);
+ if (showInfoToast) { UI.MODToaster.Show($"Preset: Original/Ryukishi"); }
+ }
+ }
+
+ public static void LoadCustomGraphicsPreset(bool showInfoToast = true)
+ {
+ BurikoMemory.Instance.GetCustomFlagPresetInstance().EnablePreset(restorePresetFromMemory: true);
+ SetTextWindowAppearanceInternal((ModPreset) GetADVNVLRyukishiModeFromFlags(), new MODMainUIController(), showInfoToast: false);
+ Core.MODSystem.instance.modTextureController.SetArtStyle(Assets.Scripts.Core.AssetManagement.AssetManager.Instance.CurrentArtsetIndex, showInfoToast: false);
+ if (showInfoToast) { UI.MODToaster.Show($"Preset: Custom"); }
+ }
+
+ public static void EnableCustomGraphicsPreset(bool showInfoToast = true)
+ {
+ BurikoMemory.Instance.GetCustomFlagPresetInstance().EnablePreset(restorePresetFromMemory: false);
+ if (showInfoToast) { UI.MODToaster.Show($"Preset: Custom"); }
+ }
+
+ public static void SetArtStyle(int artStyle, bool showInfoToast)
+ {
+ Core.MODSystem.instance.modTextureController.SetArtStyle(artStyle, showInfoToast);
+ SwitchToCustomPresetIfPresetModified(showInfoToast);
+ }
+
+ public static void SetTextWindowAppearance(ModPreset setting, bool showInfoToast = true)
+ {
+ SetTextWindowAppearanceInternal(setting, new MODMainUIController(), showInfoToast);
+ SwitchToCustomPresetIfPresetModified(showInfoToast);
+ }
+
+ private static void SetTextWindowAppearanceInternal(ModPreset setting, MODMainUIController MODMainUIController, bool showInfoToast = true)
+ {
+ if (setting == ModPreset.Console)
+ {
+ BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 0);
+ BurikoMemory.Instance.SetGlobalFlag("GADVMode", 1);
+ BurikoMemory.Instance.SetGlobalFlag("GLinemodeSp", 0);
TryRedrawTextWindowBackground(WindowFilterType.ADV);
- mODMainUIController.WideGuiPositionStore();
- mODMainUIController.ADVModeSettingStore();
+ MODMainUIController.WideGuiPositionStore();
+ MODMainUIController.ADVModeSettingStore();
string feedbackString = $"Set ADV Mode";
int toastDuration = 3;
- Core.MODSystem.instance.modTextureController.SetArtStyle(0, showInfoToast);
bool is_nvl_in_adv_region = BurikoMemory.Instance.GetFlag("NVL_in_ADV").IntValue() == 1;
if (is_nvl_in_adv_region)
{
@@ -106,44 +171,43 @@ public static void SetAndSaveADV(ModPreset setting, bool showInfoToast = true)
}
if (is_nvl_in_adv_region || showInfoToast) { MODToaster.Show(feedbackString, isEnable: true, toastDuration: toastDuration); }
}
- else if (setting == ModPreset.NVL)
+ else if (setting == ModPreset.MangaGamer)
{
+ BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 0);
BurikoMemory.Instance.SetGlobalFlag("GADVMode", 0);
BurikoMemory.Instance.SetGlobalFlag("GLinemodeSp", 2);
- BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 0);
- BurikoMemory.Instance.SetGlobalFlag("GHideCG", 0);
- BurikoMemory.Instance.SetGlobalFlag("GStretchBackgrounds", 0);
TryRedrawTextWindowBackground(WindowFilterType.Normal);
- mODMainUIController.WideGuiPositionStore();
- mODMainUIController.NVLModeSettingStore();
- Core.MODSystem.instance.modTextureController.SetArtStyle(0, showInfoToast);
+ MODMainUIController.WideGuiPositionStore();
+ MODMainUIController.NVLModeSettingStore();
if (showInfoToast) { MODToaster.Show($"Set NVL Mode", isEnable: false); }
}
else if (setting == ModPreset.OG)
{
+ BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 1);
BurikoMemory.Instance.SetGlobalFlag("GADVMode", 0);
BurikoMemory.Instance.SetGlobalFlag("GLinemodeSp", 2);
- BurikoMemory.Instance.SetGlobalFlag("GRyukishiMode", 1);
- BurikoMemory.Instance.SetGlobalFlag("GHideCG", 1);
- BurikoMemory.Instance.SetGlobalFlag("GStretchBackgrounds", 0);
TryRedrawTextWindowBackground(WindowFilterType.OG);
- mODMainUIController.RyukishiGuiPositionStore();
- mODMainUIController.RyukishiModeSettingStore();
- Core.MODSystem.instance.modTextureController.SetArtStyle(2, showInfoToast);
+ MODMainUIController.RyukishiGuiPositionStore();
+ MODMainUIController.RyukishiModeSettingStore();
if (showInfoToast) { MODToaster.Show($"Set OG Mode", isEnable: false); }
}
}
+ public static int GetADVNVLRyukishiModeFromFlags() => GetADVNVLRyukishiModeFromFlags(out bool _);
+
// This expressions for 'presetModified' should be updated each time SetAndSaveADV() above is changed,
// so that the player knows when the flags have changed from their default values for the current preset
public static int GetADVNVLRyukishiModeFromFlags(out bool presetModified)
{
+
// If background override is enabled on any preset, the preset has been modified
- presetModified = BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() != 0;
+ presetModified = false;
if (BurikoMemory.Instance.GetGlobalFlag("GRyukishiMode").IntValue() == 1)
{
+ // Original/Ryukishi Preset
presetModified = presetModified ||
+ BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() != 1 ||
BurikoMemory.Instance.GetGlobalFlag("GArtStyle").IntValue() != 2 ||
BurikoMemory.Instance.GetGlobalFlag("GADVMode").IntValue() != 0 ||
BurikoMemory.Instance.GetGlobalFlag("GLinemodeSp").IntValue() != 2 ||
@@ -155,7 +219,10 @@ public static int GetADVNVLRyukishiModeFromFlags(out bool presetModified)
}
else if (BurikoMemory.Instance.GetGlobalFlag("GADVMode").IntValue() == 1)
{
+ // Console Preset
presetModified = presetModified ||
+ BurikoMemory.Instance.GetGlobalFlag("GLipSync").IntValue() != 1 ||
+ BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() != 0 ||
BurikoMemory.Instance.GetGlobalFlag("GArtStyle").IntValue() != 0 ||
BurikoMemory.Instance.GetGlobalFlag("GADVMode").IntValue() != 1 ||
BurikoMemory.Instance.GetGlobalFlag("GLinemodeSp").IntValue() != 0 ||
@@ -167,8 +234,10 @@ public static int GetADVNVLRyukishiModeFromFlags(out bool presetModified)
}
else
{
+ // Mangagamer Preset
presetModified = presetModified ||
- BurikoMemory.Instance.GetGlobalFlag("GArtStyle").IntValue() != 0 ||
+ BurikoMemory.Instance.GetGlobalFlag("GBackgroundSet").IntValue() != 0 ||
+ BurikoMemory.Instance.GetGlobalFlag("GArtStyle").IntValue() != 1 ||
BurikoMemory.Instance.GetGlobalFlag("GADVMode").IntValue() != 0 ||
BurikoMemory.Instance.GetGlobalFlag("GLinemodeSp").IntValue() != 2 ||
BurikoMemory.Instance.GetGlobalFlag("GRyukishiMode").IntValue() != 0 ||
@@ -179,6 +248,15 @@ public static int GetADVNVLRyukishiModeFromFlags(out bool presetModified)
}
}
+ public static void SwitchToCustomPresetIfPresetModified(bool showInfoToast)
+ {
+ GetADVNVLRyukishiModeFromFlags(out bool presetModified);
+ if(presetModified && !BurikoMemory.Instance.GetCustomFlagPresetInstance().Enabled)
+ {
+ EnableCustomGraphicsPreset(showInfoToast: showInfoToast);
+ }
+ }
+
public static void EnableNVLModeINADVMode()
{
BurikoMemory.Instance.SetFlag("NVL_in_ADV", 1);
@@ -279,10 +357,17 @@ static int _IncrementFlagWithRollover(string flagName, int minValueInclusive, in
public static bool ToggleFlagAndSave(string flagName)
{
int newValue = (BurikoMemory.Instance.GetGlobalFlag(flagName).IntValue() + 1) % 2;
- BurikoMemory.Instance.SetGlobalFlag(flagName, newValue);
+ SetFlagFromUserInput(flagName, newValue, showInfoToast: false);
return newValue == 1;
}
+
+ public static void SetFlagFromUserInput(string flagName, int newValue, bool showInfoToast)
+ {
+ BurikoMemory.Instance.SetGlobalFlag(flagName, newValue);
+ SwitchToCustomPresetIfPresetModified(showInfoToast);
+ }
+
public static string VideoOpeningDescription(int videoOpeningValue)
{
switch (videoOpeningValue)
diff --git a/MOD.Scripts.UI/MODCustomFlagPreset.cs b/MOD.Scripts.UI/MODCustomFlagPreset.cs
new file mode 100644
index 00000000..7748a1f4
--- /dev/null
+++ b/MOD.Scripts.UI/MODCustomFlagPreset.cs
@@ -0,0 +1,108 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MOD.Scripts.UI
+{
+ ///
+ /// This class aids in enabling/disabling a group of flags at once
+ ///
+ class MODCustomFlagPreset
+ {
+ ///
+ /// This special flag/key will be used to determine if the custom preset is enabled or not
+ /// It should start with a $ sign, to avoid conflicting with normal flags.
+ ///
+ const string ENABLED_KEY = "$customPresetEnabled";
+
+ ///
+ /// This list contains flags which will be saved/restored with the custom preset
+ ///
+ List FLAGS_TO_SERIALIZE = new List
+ {
+ "GLipSync",
+ "GBackgroundSet",
+ "GArtStyle",
+ "GADVMode",
+ "GLinemodeSp",
+ "GRyukishiMode",
+ "GHideCG",
+ "GStretchBackgrounds"
+ };
+
+ // All of this class's state is kept in this Dictionary, for easy serialization.
+ // To restore the state, re-assign this variable with the new data.
+ public Dictionary Flags { get; set; }
+
+ public MODCustomFlagPreset()
+ {
+ this.Flags = new Dictionary();
+ }
+
+ ///
+ /// This keeps track of whether the custom preset is enabled.
+ ///
+ public bool Enabled
+ {
+ get
+ {
+ if (Flags.TryGetValue(ENABLED_KEY, out int value))
+ {
+ return value == 1;
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+
+ public void EnablePreset(bool restorePresetFromMemory)
+ {
+ if(restorePresetFromMemory)
+ {
+ RestorePresetFromMemory();
+ }
+
+ Flags[ENABLED_KEY] = 1;
+ }
+
+ ///
+ /// Copy global flags to preset every time preset mod changes from enabled -> disabled.
+ // This ensure flags are saved when you switch to another preset.
+ // This doesn't handle the case when exiting the game, which must be handled manually using SavePresetToMemory().
+ ///
+ public void DisablePresetAndSavePresetToMemory()
+ {
+ // Save all preset-related flags to memory
+ if(Enabled)
+ {
+ SavePresetToMemory();
+ }
+
+ // Set the special "enabled" key to false in memory
+ Flags[ENABLED_KEY] = 0;
+ }
+
+ public void SavePresetToMemory()
+ {
+ foreach (string flagName in FLAGS_TO_SERIALIZE)
+ {
+ Flags[flagName] = Assets.Scripts.Core.Buriko.BurikoMemory.Instance.GetGlobalFlag(flagName).IntValue();
+ }
+ }
+
+ private void RestorePresetFromMemory()
+ {
+ foreach (KeyValuePair pair in Flags)
+ {
+ if (pair.Key.StartsWith("$"))
+ {
+ continue;
+ }
+
+ Assets.Scripts.Core.Buriko.BurikoMemory.Instance.SetGlobalFlag(pair.Key, pair.Value);
+ }
+ }
+ }
+}
diff --git a/MOD.Scripts.UI/MODMenu.cs b/MOD.Scripts.UI/MODMenu.cs
index 06b897f6..00f8c008 100644
--- a/MOD.Scripts.UI/MODMenu.cs
+++ b/MOD.Scripts.UI/MODMenu.cs
@@ -13,7 +13,7 @@
namespace MOD.Scripts.UI
{
- public enum ModMenuMode
+ public enum ModSubMenu
{
Normal,
AudioSetup,
@@ -30,7 +30,6 @@ public class MODMenu
private MODSimpleTimer defaultToolTipTimer;
private MODSimpleTimer startupWatchdogTimer;
private bool startupFailed;
- private bool anyButtonPressed;
Vector2 scrollPosition;
Vector2 leftDebugColumnScrollPosition;
private Rect debugWindowRect;
@@ -86,6 +85,9 @@ public void Update()
public void LateUpdate()
{
+ // Hide the menu on right-click
+ // This must be done in LateUpdate() rather than Update(),
+ // otherwise the right-click event will also open the in-game right-click menu
if (Input.GetMouseButtonDown(1))
{
this.UserHide();
@@ -147,7 +149,8 @@ private void OnGUIDebugWindow(int windowID)
}
///
- /// Must be called from an OnGUI()
+ /// This function MUST be called from an OnGUI(), otherwise Unity won't work
+ /// properly when the immediate mode GUI functions are called.
///
public void OnGUIFragment()
{
@@ -172,12 +175,14 @@ public void OnGUIFragment()
}
}
+ // Assume that the game started up correctly if the flow.txt game script was reached
if(BurikoScriptSystem.Instance.FlowWasReached)
{
this.startupFailed = false;
}
- // Button to open the Mod Menu on the Config Screen
+ // This adds an "Open Mod Menu" button to the Config Screen
+ // (the normal settings screen that comes with the stock game)
if (gameSystem.GameState == GameState.ConfigScreen)
{
if (gameSystem.ConfigManager() != null)
@@ -200,9 +205,10 @@ public void OnGUIFragment()
GUILayout.EndArea();
}
+ // If you need to initialize things just once before the menu opens, rather than every frame
+ // you can do it in the OnBeforeMenuVisible() function below.
if (visible && !lastMenuVisibleStatus)
{
- // Executes just before menu becomes visible
currentMenu.OnBeforeMenuVisible();
}
lastMenuVisibleStatus = visible;
@@ -210,7 +216,7 @@ public void OnGUIFragment()
if (visible)
{
- float totalAreaWidth = styleManager.Group.menuWidth; // areaWidth + toolTipWidth;
+ float totalAreaWidth = styleManager.Group.menuWidth;
float areaWidth = Mathf.Round(totalAreaWidth * 9/16);
float toolTipWidth = Mathf.Round(totalAreaWidth * 7/16);
@@ -227,19 +233,24 @@ public void OnGUIFragment()
float innerMargin = 4f;
- // Radio buttons
+ // This contains the the entire menu, and draws a white border around it
GUILayout.BeginArea(new Rect(areaPosX, areaPosY, areaWidth + toolTipWidth, areaHeight), styleManager.modMenuAreaStyle);
+
+ // This displays the left hand side of the menu which contains the option buttons and headings
{
GUILayout.BeginArea(new Rect(innerMargin, innerMargin, areaWidth-innerMargin, areaHeight-innerMargin), styleManager.modGUIBackgroundTextureTransparent);
// Note: GUILayout.Height is adjusted to be slightly smaller, otherwise not all content is visible/scroll bar is slightly cut off.
scrollPosition = GUILayout.BeginScrollView(scrollPosition, GUILayout.Width(areaWidth), GUILayout.Height(areaHeight-10));
+ // 'currentMenu' is reassigned to switch to different sub-menus
+ // please see the SetSubMenu() function
currentMenu.OnGUI();
GUILayout.EndScrollView();
GUILayout.EndArea();
}
+ // This displays the right hand side of the menu which contains descriptions of each option.
// Descriptions for each button are shown on hover, like a tooltip
{
GUILayout.BeginArea(new Rect(toolTipPosX, innerMargin, toolTipWidth- innerMargin, areaHeight-innerMargin), styleManager.modGUIBackgroundTextureTransparent);
@@ -292,35 +303,43 @@ public void OnGUIFragment()
}
GUILayout.EndArea();
- if(MODRadio.anyRadioPressed || anyButtonPressed)
+ if(MODRadio.anyRadioPressed || MODMenuCommon.anyButtonPressed)
{
GameSystem.Instance.AudioController.PlaySystemSound(MODSound.GetSoundPathFromEnum(buttonClickSound));
MODRadio.anyRadioPressed = false;
- anyButtonPressed = false;
+ MODMenuCommon.anyButtonPressed = false;
}
}
}
+ // This temporarily changes button click sound for one frame.
+ // The button click sound will revert to the default click sound on the next frame.
public void OverrideClickSound(GUISound sound)
{
buttonClickSound = sound;
}
- public void SetMode(ModMenuMode menuMode)
+ // The mod menu has different sub-menus, which can be switched between by calling this function.
+ // If the sub-menus have any state, it will be retained during switching, and even if the menu is closed and reopened.
+ public void SetSubMenu(ModSubMenu subMenu)
{
- switch (menuMode)
+ switch (subMenu)
{
- case ModMenuMode.AudioSetup:
+ case ModSubMenu.AudioSetup:
currentMenu = audioSetupMenu;
break;
- case ModMenuMode.Normal:
+ case ModSubMenu.Normal:
default:
currentMenu = normalMenu;
break;
}
}
+ // This function attempts to show the menu, but please note:
+ // - on the Save / Load screen, it will instead tell you to close the Save/Load screen
+ // - the menu might open after a short delay, due to using a delegate to close
+ // the currently open menu. Please keep this in mind if you're relying on the menu opening immediately.
public void Show()
{
void ForceShow()
@@ -349,8 +368,8 @@ void ForceShow()
}
///
- /// This function should be called when the user has initiated the hiding of the menu.
- /// This function call might be ignored if the menu disallows closing - call
+ /// This function hides the menu if the menu allows it.
+ /// Use ForceHide() to forcibly hide the menu.
///
public void UserHide()
{
@@ -360,6 +379,10 @@ public void UserHide()
}
}
+ ///
+ /// This function toggles the menu on/off if the menu allows it.
+ /// Use ForceToggleVisibility() to forcibly toggle the menu.
+ ///
public void UserToggleVisibility()
{
if (currentMenu.UserCanClose())
@@ -368,6 +391,9 @@ public void UserToggleVisibility()
}
}
+ ///
+ /// This function hides the menu, even if the if the menu prefers not to be hidden.
+ ///
public void ForceHide()
{
this.visible = false;
@@ -375,6 +401,9 @@ public void ForceHide()
gameSystem.ShowUIControls();
}
+ ///
+ /// This function toggles the menu, even if the if the menu prefers not to be toggled.
+ ///
public void ForceToggleVisibility()
{
if (this.visible)
diff --git a/MOD.Scripts.UI/MODMenuAudioSetup.cs b/MOD.Scripts.UI/MODMenuAudioSetup.cs
index 9f3c1ef6..df96c873 100644
--- a/MOD.Scripts.UI/MODMenuAudioSetup.cs
+++ b/MOD.Scripts.UI/MODMenuAudioSetup.cs
@@ -33,7 +33,7 @@ public void OnGUI()
if (GetGlobal("GAudioSet") != 0 && Button(new GUIContent("Click here when you're finished.")))
{
- modMenu.SetMode(ModMenuMode.Normal);
+ modMenu.SetSubMenu(ModSubMenu.Normal);
modMenu.ForceHide();
}
}
diff --git a/MOD.Scripts.UI/MODMenuCommon.cs b/MOD.Scripts.UI/MODMenuCommon.cs
index 44e84108..7747acf1 100644
--- a/MOD.Scripts.UI/MODMenuCommon.cs
+++ b/MOD.Scripts.UI/MODMenuCommon.cs
@@ -8,6 +8,7 @@ namespace MOD.Scripts.UI
{
static class MODMenuCommon
{
+ public static bool anyButtonPressed;
public static void Label(string label)
{
GUILayout.Label(label, MODStyleManager.OnGUIInstance.Group.label);
@@ -20,7 +21,15 @@ public static void HeadingLabel(string label)
public static bool Button(GUIContent guiContent, bool selected = false)
{
- return GUILayout.Button(guiContent, selected ? MODStyleManager.OnGUIInstance.Group.selectedButton : MODStyleManager.OnGUIInstance.Group.button);
+ if(GUILayout.Button(guiContent, selected ? MODStyleManager.OnGUIInstance.Group.selectedButton : MODStyleManager.OnGUIInstance.Group.button))
+ {
+ anyButtonPressed = true;
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
public static int GetGlobal(string flagName) => BurikoMemory.Instance.GetGlobalFlag(flagName).IntValue();
diff --git a/MOD.Scripts.UI/MODMenuNormal.cs b/MOD.Scripts.UI/MODMenuNormal.cs
index 8f97945a..01adcbeb 100644
--- a/MOD.Scripts.UI/MODMenuNormal.cs
+++ b/MOD.Scripts.UI/MODMenuNormal.cs
@@ -23,6 +23,14 @@ class MODMenuNormal : MODMenuModuleInterface
private readonly MODRadio radioHideCG;
private readonly MODRadio radioBackgrounds;
private readonly MODRadio radioArtSet;
+ private readonly MODRadio radioStretchBackgrounds;
+ private readonly MODRadio radioTextWindowModeAndCrop;
+
+ private readonly MODTabControl tabControl;
+
+ private readonly MODCustomFlagPreset customFlagPreset;
+
+ private bool showDeveloperSubmenu;
public MODMenuNormal(MODMenu modMenu, MODMenuAudioOptions audioOptionsMenu)
{
@@ -33,10 +41,9 @@ public MODMenuNormal(MODMenu modMenu, MODMenuAudioOptions audioOptionsMenu)
hasOGBackgrounds = MODActions.HasOGBackgrounds();
defaultArtsetDescriptions = new GUIContent[] {
- new GUIContent("Console", "Use the Console sprites and backgrounds"),
- new GUIContent("Remake", "Use Mangagamer's remake sprites with Console backgrounds"),
- new GUIContent("Original", "Use Original/Ryukishi sprites and backgrounds (if available - OG backgrounds not available for Console Arcs)\n\n" +
- "Warning: Most users should use the Original/Ryukishi preset at the top of this menu!"),
+ new GUIContent("Console", "Use the Console sprites"),
+ new GUIContent("MangaGamer", "Use Mangagamer's remake sprites"),
+ new GUIContent("Original", "Use Original/Ryukishi sprites"),
};
string baseCensorshipDescription = @"
@@ -80,155 +87,207 @@ Sets the script censorship level
new GUIContent("Hide CGs", "Disables all CGs (mainly for use with the Original/Ryukishi preset)"),
});
- radioBackgrounds = new MODRadio("Override Art Set Backgrounds", new GUIContent[]{
- new GUIContent("Default BGs", "Use the default backgrounds for the current artset"),
- new GUIContent("Console BGs", "Force Console backgrounds, regardless of the artset"),
- new GUIContent("Original BGs", "Force Original/Ryukishi backgrounds, regardless of the artset"),
- new GUIContent("Original Stretched", "Force Original/Ryukishi backgrounds, stretched to fit, regardless of the artset\n\n" +
- "WARNING: When using this option, you should have ADV/NVL mode selected, otherwise sprites will be cut off, and UI will appear in the wrong place"),
+ radioBackgrounds = new MODRadio("Background Style", new GUIContent[]{
+ new GUIContent("Console BGs", "Use Console backgrounds"),
+ new GUIContent("Original BGs", "Use Original/Ryukishi backgrounds."),
+ }, itemsPerRow: 2);
+
+ radioStretchBackgrounds = new MODRadio("Background Stretching", new GUIContent[]
+ {
+ new GUIContent("BG Stretching Off", "Makes backgrounds as big as possible without any stretching (Keep Aspect Ratio)"),
+ new GUIContent("BG Stretching On", "Stretches backgrounds to fit the screen (Ignore Aspect Ratio)\n\n" +
+ "Mainly for use with the Original BGs, which are in 4:3 aspect ratio."),
+ });
+
+ radioArtSet = new MODRadio("Sprite Style", defaultArtsetDescriptions, itemsPerRow: 3);
+
+ radioTextWindowModeAndCrop = new MODRadio("Text Window Appearance", new GUIContent[]{
+ new GUIContent("ADV Mode", "This option:\n" +
+ "- Makes text show at the bottom of the screen in a textbox\n" +
+ "- Shows the name of the current character on the textbox\n"),
+ new GUIContent("NVL Mode", "This option:\n" +
+ "- Makes text show across the whole screen\n"),
+ new GUIContent("Original", "This option:\n" +
+ "- Darkens the whole screen to emulate the original game\n" +
+ "- Makes text show only in a 4:3 section of the screen (narrower than NVL mode)\n"),
}, itemsPerRow: 2);
- radioArtSet = new MODRadio("Choose Art Set", defaultArtsetDescriptions, itemsPerRow: 3);
+ tabControl = new MODTabControl(new List
+ {
+ new MODTabControl.TabProperties("Gameplay", "Voice Matching and Opening Videos", GameplayTabOnGUI),
+ new MODTabControl.TabProperties("Graphics", "Sprites, Backgrounds, CGs, Resolution", GraphicsTabOnGUI),
+ new MODTabControl.TabProperties("Audio", "BGM and SE options", AudioTabOnGUI),
+ new MODTabControl.TabProperties("Troubleshooting", "Tools to help you if something goes wrong", TroubleShootingTabOnGUI),
+ });
+
+ customFlagPreset = Assets.Scripts.Core.Buriko.BurikoMemory.Instance.GetCustomFlagPresetInstance();
}
public void OnGUI()
{
- HeadingLabel("Basic Options");
+ tabControl.OnGUI();
+ }
+
+ public void OnBeforeMenuVisible() {
+ // Update the artset radio buttons/descriptions, as these are set by ModAddArtset() calls in init.txt at runtime
+ // Technically only need to do this once after init.txt has been called, but it's easier to just do it each time menu is opened
+ GUIContent[] descriptions = Core.MODSystem.instance.modTextureController.GetArtStyleDescriptions();
+ for (int i = 0; i < descriptions.Length; i++)
+ {
+ if (i < this.defaultArtsetDescriptions.Length)
+ {
+ descriptions[i] = this.defaultArtsetDescriptions[i];
+ }
+ }
+ this.radioArtSet.SetContents(descriptions);
+ resolutionMenu.OnBeforeMenuVisible();
+ audioOptionsMenu.OnBeforeMenuVisible();
+ }
+
+ private void GraphicsTabOnGUI()
+ {
Label("Graphics Presets (Hotkey: F1)");
{
GUILayout.BeginHorizontal();
int advNVLRyukishiMode = MODActions.GetADVNVLRyukishiModeFromFlags(out bool presetModified);
- if (Button(new GUIContent(advNVLRyukishiMode == 0 && presetModified ? "ADV (custom)" : "ADV", "This preset:\n" +
+ if (Button(new GUIContent("Console", "This preset:\n" +
"- Makes text show at the bottom of the screen in a textbox\n" +
"- Shows the name of the current character on the textbox\n" +
- "- Uses the console sprites and backgrounds\n" +
+ "- Uses the console sprites (with lipsync) and console backgrounds\n" +
"- Displays in 16:9 widescreen\n\n" +
- "Note that sprites and backgrounds can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: advNVLRyukishiMode == 0))
+ "Note that sprites and backgrounds can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: !customFlagPreset.Enabled && !presetModified && advNVLRyukishiMode == 0))
{
- MODActions.SetAndSaveADV(MODActions.ModPreset.ADV, showInfoToast: false);
+ MODActions.SetGraphicsPreset(MODActions.ModPreset.Console, showInfoToast: false);
}
- if (Button(new GUIContent(advNVLRyukishiMode == 1 && presetModified ? "NVL (custom)" : "NVL", "This preset:\n" +
+ if (Button(new GUIContent("MangaGamer", "This preset:\n" +
"- Makes text show across the whole screen\n" +
"- Uses the console sprites and backgrounds\n" +
"- Displays in 16:9 widescreen\n\n" +
- "Note that sprites and backgrounds can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: advNVLRyukishiMode == 1))
+ "Note that sprites and backgrounds can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: !customFlagPreset.Enabled && !presetModified && advNVLRyukishiMode == 1))
{
- MODActions.SetAndSaveADV(MODActions.ModPreset.NVL, showInfoToast: false);
+ MODActions.SetGraphicsPreset(MODActions.ModPreset.MangaGamer, showInfoToast: false);
}
if (this.hasOGBackgrounds &&
- Button(new GUIContent(advNVLRyukishiMode == 2 && presetModified ? "Original/Ryukishi (custom)" : "Original/Ryukishi", "This preset makes the game behave similarly to the unmodded game:\n" +
+ Button(new GUIContent("Original/Ryukishi", "This preset makes the game behave similarly to the unmodded game:\n" +
"- Displays backgrounds in 4:3 'standard' aspect\n" +
"- CGs are disabled (Can be re-enabled, see 'Show/Hide CGs')\n" +
"- Switches to original sprites and backgrounds\n\n" +
- "Note that sprites, backgrounds, and CG hiding can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: advNVLRyukishiMode == 2))
+ "Note that sprites, backgrounds, and CG hiding can be overridden by setting the 'Choose Art Set' & 'Override Art Set Backgrounds' options under 'Advanced Options', if available"), selected: !customFlagPreset.Enabled && !presetModified && advNVLRyukishiMode == 2))
{
- MODActions.SetAndSaveADV(MODActions.ModPreset.OG, showInfoToast: false);
+ MODActions.SetGraphicsPreset(MODActions.ModPreset.OG, showInfoToast: false);
+ }
+
+ if (Button(new GUIContent("Custom", "Your own custom preset, using the options below.\n\n" +
+ "This custom preset will be saved, even when you switch to the other presets."), selected: customFlagPreset.Enabled))
+ {
+ MODActions.LoadCustomGraphicsPreset(showInfoToast: false);
}
GUILayout.EndHorizontal();
}
- if (this.radioCensorshipLevel.OnGUIFragment(GetGlobal("GCensor")) is int censorLevel)
- {
- SetGlobal("GCensor", censorLevel);
- };
+ HeadingLabel("Advanced Options");
if (this.radioLipSync.OnGUIFragment(GetGlobal("GLipSync")) is int lipSyncEnabled)
{
- SetGlobal("GLipSync", lipSyncEnabled);
+ MODActions.SetFlagFromUserInput("GLipSync", lipSyncEnabled, showInfoToast: false);
};
- if (this.radioOpenings.OnGUIFragment(GetGlobal("GVideoOpening") - 1) is int openingVideoLevelZeroIndexed)
- {
- SetGlobal("GVideoOpening", openingVideoLevelZeroIndexed + 1);
- };
-
- this.audioOptionsMenu.OnGUI();
-
- HeadingLabel("Advanced Options");
-
- this.audioOptionsMenu.AdvancedOnGUI();
-
if (this.radioHideCG.OnGUIFragment(GetGlobal("GHideCG")) is int hideCG)
{
- SetGlobal("GHideCG", hideCG);
+ MODActions.SetFlagFromUserInput("GHideCG", hideCG, showInfoToast: false);
};
if (this.radioArtSet.OnGUIFragment(Core.MODSystem.instance.modTextureController.GetArtStyle()) is int artStyle)
{
- SetGlobal("GStretchBackgrounds", 0);
- Core.MODSystem.instance.modTextureController.SetArtStyle(artStyle, showInfoToast: false);
+ MODActions.SetArtStyle(artStyle, showInfoToast: false);
}
if (this.hasOGBackgrounds)
{
- int currentBackground = GetGlobal("GBackgroundSet");
- if (currentBackground == 2)
+ if (this.radioBackgrounds.OnGUIFragment(GetGlobal("GBackgroundSet")) is int background)
{
- if (GetGlobal("GStretchBackgrounds") == 1)
- {
- currentBackground = 3;
- }
+ MODActions.SetFlagFromUserInput("GBackgroundSet", background, showInfoToast: false);
+ GameSystem.Instance.SceneController.ReloadAllImages();
}
- if (this.radioBackgrounds.OnGUIFragment(currentBackground) is int background)
+
+ if (this.radioStretchBackgrounds.OnGUIFragment(GetGlobal("GStretchBackgrounds")) is int stretchBackgrounds)
{
- if (background == 3)
- {
- SetGlobal("GStretchBackgrounds", 1);
- SetGlobal("GBackgroundSet", 2);
- }
- else
- {
- SetGlobal("GStretchBackgrounds", 0);
- SetGlobal("GBackgroundSet", background);
- }
+ MODActions.SetFlagFromUserInput("GStretchBackgrounds", stretchBackgrounds, showInfoToast: false);
GameSystem.Instance.SceneController.ReloadAllImages();
}
}
+ if (this.radioTextWindowModeAndCrop.OnGUIFragment(MODActions.GetADVNVLRyukishiModeFromFlags()) is int windowMode)
+ {
+ MODActions.SetTextWindowAppearance((MODActions.ModPreset) windowMode, showInfoToast: false);
+ GameSystem.Instance.SceneController.ReloadAllImages();
+ }
+
+ HeadingLabel("Resolution");
+
resolutionMenu.OnGUI();
+ }
+
+ private void GameplayTabOnGUI()
+ {
+ if (this.radioCensorshipLevel.OnGUIFragment(GetGlobal("GCensor")) is int censorLevel)
+ {
+ SetGlobal("GCensor", censorLevel);
+ };
+
+ if (this.radioOpenings.OnGUIFragment(GetGlobal("GVideoOpening") - 1) is int openingVideoLevelZeroIndexed)
+ {
+ SetGlobal("GVideoOpening", openingVideoLevelZeroIndexed + 1);
+ };
+ }
- GUILayout.Space(10);
- OnGUIRestoreSettings();
+ private void AudioTabOnGUI()
+ {
+ this.audioOptionsMenu.OnGUI();
- HeadingLabel("Troubleshooting");
+ HeadingLabel("Advanced Options");
+
+ this.audioOptionsMenu.AdvancedOnGUI();
+ }
+
+
+ private void TroubleShootingTabOnGUI()
+ {
Label("Save Files and Log Files");
MODMenuSupport.ShowSupportButtons(content => Button(content));
- Label("Developer");
- GUILayout.BeginHorizontal();
- if (Button(new GUIContent("Toggle debug menu (Shift-F9)", "Toggle the debug menu")))
- {
- modMenu.ToggleDebugMenu();
- }
- if (Button(new GUIContent("Toggle flag menu (Shift-F10)", "Toggle the flag menu. Toggle Multiple times for more options.\n\nNote: 3rd and 4th panels are only shown if GMOD_DEBUG_MODE is true.")))
+ HeadingLabel("Developer Tools");
+
+ if(showDeveloperSubmenu)
{
- MODActions.ToggleFlagMenu();
- }
- GUILayout.EndHorizontal();
- }
+ OnGUIRestoreSettings();
- public void OnBeforeMenuVisible() {
- // Update the artset radio buttons/descriptions, as these are set by ModAddArtset() calls in init.txt at runtime
- // Technically only need to do this once after init.txt has been called, but it's easier to just do it each time menu is opened
- GUIContent[] descriptions = Core.MODSystem.instance.modTextureController.GetArtStyleDescriptions();
- for (int i = 0; i < descriptions.Length; i++)
+ Label("Developer Debug Menu");
+ GUILayout.BeginHorizontal();
+ if (Button(new GUIContent("Toggle debug menu (Shift-F9)", "Toggle the debug menu")))
+ {
+ modMenu.ToggleDebugMenu();
+ }
+ if (Button(new GUIContent("Toggle flag menu (Shift-F10)", "Toggle the flag menu. Toggle Multiple times for more options.\n\nNote: 3rd and 4th panels are only shown if GMOD_DEBUG_MODE is true.")))
+ {
+ MODActions.ToggleFlagMenu();
+ }
+ GUILayout.EndHorizontal();
+ }
+ else
{
- if (i < this.defaultArtsetDescriptions.Length)
+ if (Button(new GUIContent("Show Developer Tools: Only click if asked by developers", "Show the Developer Tools.\n\nOnly click this button if you're asked to by the developers.")))
{
- descriptions[i] = this.defaultArtsetDescriptions[i];
+ showDeveloperSubmenu = true;
}
}
- this.radioArtSet.SetContents(descriptions);
-
- resolutionMenu.OnBeforeMenuVisible();
- audioOptionsMenu.OnBeforeMenuVisible();
}
private void OnGUIRestoreSettings()
diff --git a/MOD.Scripts.UI/MODMenuSupport.cs b/MOD.Scripts.UI/MODMenuSupport.cs
index 625435c3..9a10bc7a 100644
--- a/MOD.Scripts.UI/MODMenuSupport.cs
+++ b/MOD.Scripts.UI/MODMenuSupport.cs
@@ -52,7 +52,7 @@ public static void ShowSupportButtons(Func buttonRenderer)
}
if (buttonRenderer(new GUIContent("Show Saves", "Clearing your save files can fix some issues with game startup, and resets all mod flags.\n\n" +
- "- WARNING: Steam sync will restore your saves if you manually delete them! Therefore, remember to disable steam sync, otherwise your saves will magically reappear!\n" +
+ "- WARNING: Steam cloud will restore your saves if you manually delete them! Therefore, remember to disable steam cloud, otherwise your saves will magically reappear!\n" +
"- The 'global.dat' file stores your global unlock process and mod flags\n" +
"- The 'qsaveX.dat' and 'saveXXX.dat' files contain individual save files. Note that these becoming corrupted can break your game\n" +
"- It's recommended to take a backup of all your saves before you modify them")))
diff --git a/MOD.Scripts.UI/MODTabControl.cs b/MOD.Scripts.UI/MODTabControl.cs
new file mode 100644
index 00000000..a8c52743
--- /dev/null
+++ b/MOD.Scripts.UI/MODTabControl.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+using static MOD.Scripts.UI.MODMenuCommon;
+
+namespace MOD.Scripts.UI
+{
+ class MODTabControl
+ {
+ public class TabProperties
+ {
+ public string name;
+ public string description;
+ public Action tabRenderFunction;
+
+ public TabProperties(string name, string description, Action tabRenderFunction)
+ {
+ this.name = name;
+ this.description = description;
+ this.tabRenderFunction = tabRenderFunction;
+ }
+ }
+
+ private int currentTab;
+ private List tabProperties;
+ private readonly MODRadio radioTabs;
+
+ public MODTabControl(List tabProperties)
+ {
+ this.tabProperties = tabProperties;
+ this.radioTabs = new MODRadio("", tabProperties.Select(x => new GUIContent(x.name, x.description)).ToArray());
+ }
+
+ public void OnGUI()
+ {
+ if (radioTabs.OnGUIFragment(this.currentTab, hideLabel: true) is int tab)
+ {
+ this.currentTab = tab;
+ }
+
+ // Probably not possible, but restrict the current tab to be within limits
+ currentTab = currentTab % tabProperties.Count;
+
+ HeadingLabel(tabProperties[currentTab].name);
+
+ // Render the current tab
+ tabProperties[currentTab].tabRenderFunction();
+ }
+ }
+}