diff --git a/Assembly-CSharp.csproj b/Assembly-CSharp.csproj index df39984d..7eb18b2c 100644 --- a/Assembly-CSharp.csproj +++ b/Assembly-CSharp.csproj @@ -240,12 +240,14 @@ + + diff --git a/Assets.Scripts.Core.Buriko/BurikoSaveManager.cs b/Assets.Scripts.Core.Buriko/BurikoSaveManager.cs index c837c023..c81ef9eb 100644 --- a/Assets.Scripts.Core.Buriko/BurikoSaveManager.cs +++ b/Assets.Scripts.Core.Buriko/BurikoSaveManager.cs @@ -77,10 +77,15 @@ private void GetSaveData(int slot, string path) throw new FileLoadException("Save file does not appear to be valid! Invalid header."); } int num = binaryReader.ReadInt32(); - if (num != 1) - { - throw new FileLoadException("Save file does not appear to be valid! Invalid version number."); - } + // Note: On 01-01-2024, Ch.8 removed the save version check, so that saves with a version other than 1 + // could be loaded. Currently, there are only two versions 1 (initial version) and 2 (priority included in save file) + // + // Please note that this means older versions of the DLL won't be able to load new saves, so you won't be able to + // downgrade DLL version and keep your save after this. + // if (num != 1) + // { + // throw new FileLoadException("Save file does not appear to be valid! Invalid version number."); + // } saveEntry2.Time = DateTime.FromBinary(binaryReader.ReadInt64()); string textJp = binaryReader.ReadString(); string text = saveEntry2.Text = binaryReader.ReadString(); diff --git a/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs b/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs index 34c13d29..59ea034e 100644 --- a/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs +++ b/Assets.Scripts.Core.Buriko/BurikoScriptFile.cs @@ -2854,8 +2854,7 @@ private BurikoVariable OperationMODSetMainFontOutlineWidth() { SetOperationType("MODSetMainFontOutlineWidth"); int width = ReadVariable().IntValue(); - GameSystem.Instance.OutlineWidth = width / 100f; - GameSystem.Instance.MainUIController.TextWindow.outlineWidth = GameSystem.Instance.OutlineWidth; + MODFontAdjuster.SetFontOutlineWidth(width/100f); return BurikoVariable.Null; } @@ -3015,6 +3014,27 @@ public BurikoVariable OperationMODGenericCall() } break; + case "NormalFontWeight": + if(int.TryParse(callParameters, out int normalFontWeightPercent)) + { + MODFontAdjuster.SetNormalFontWeight(normalFontWeightPercent / 100.0f); + } + break; + + case "BoldFontWeight": + if (int.TryParse(callParameters, out int boldFontWeightPercent)) + { + MODFontAdjuster.SetBoldFontWeight(boldFontWeightPercent / 100.0f); + } + break; + + case "FaceDilate": + if (int.TryParse(callParameters, out int faceDilate)) + { + MODFontAdjuster.SetFaceDilation(faceDilate / 100.0f); + } + break; + default: Logger.Log($"WARNING: Unknown ModGenericCall ID '{callID}'"); break; diff --git a/Assets.Scripts.Core.Buriko/BurikoScriptSystem.cs b/Assets.Scripts.Core.Buriko/BurikoScriptSystem.cs index 9f52225d..a29c9e0d 100644 --- a/Assets.Scripts.Core.Buriko/BurikoScriptSystem.cs +++ b/Assets.Scripts.Core.Buriko/BurikoScriptSystem.cs @@ -33,6 +33,8 @@ public class BurikoScriptSystem : IScriptInterpreter public bool FlowWasReached { get; private set; } + public static int SaveVersion = 1; + public static BurikoScriptSystem Instance { get; @@ -238,7 +240,7 @@ public void TakeSaveSnapshot(string text = "") using (BinaryWriter binaryWriter = new BinaryWriter(memoryStream)) { binaryWriter.Write("MGSV".ToCharArray(0, 4)); - binaryWriter.Write(1); + binaryWriter.Write(2); binaryWriter.Write(DateTime.Now.ToBinary()); if (text == string.Empty) { @@ -359,8 +361,9 @@ public void LoadGame(int slotnum) int num = binaryReader.ReadInt32(); if (num != 1) { - throw new FileLoadException("Save file does not appear to be valid! Invalid version number."); + SaveVersion = num; } + Debug.Log("Loading save from version: " + num); binaryReader.ReadInt64(); string text = binaryReader.ReadString(); string text2 = binaryReader.ReadString(); diff --git a/Assets.Scripts.Core.Scene/Layer.cs b/Assets.Scripts.Core.Scene/Layer.cs index a563d907..935954a9 100644 --- a/Assets.Scripts.Core.Scene/Layer.cs +++ b/Assets.Scripts.Core.Scene/Layer.cs @@ -62,9 +62,17 @@ public class Layer : MonoBehaviour public bool FadingOut; - private float startRange; + private float startRange + { + get; + set; + } - private float targetRange; + private float targetRange + { + get; + set; + } public Vector3 targetPosition = new Vector3(0f, 0f, 0f); @@ -660,6 +668,7 @@ public void FadeTo(float alpha, float time) iTween.Stop(base.gameObject); startRange = targetRange; targetRange = alpha; + targetAlpha = alpha; iTween.ValueTo(base.gameObject, iTween.Hash("from", startRange, "to", targetRange, "time", time, "onupdate", "SetRange", "oncomplete", "FinishFade")); } @@ -776,6 +785,7 @@ public void ReloadTexture() public void ReleaseTextures() { + FadingOut = false; if (!(primary == null)) { ReleaseSecondaryTexture(); @@ -791,7 +801,6 @@ public void ReleaseTextures() Object.Destroy(mesh); mesh = null; meshFilter.mesh = null; - FadingOut = false; shaderType = 0; targetAngle = 0f; } @@ -893,6 +902,7 @@ public void Serialize(BinaryWriter br) br.Write(targetAlpha); br.Write((int)alignment); br.Write(shaderType); + br.Write(Priority); } private void Awake() diff --git a/Assets.Scripts.Core.Scene/SceneController.cs b/Assets.Scripts.Core.Scene/SceneController.cs index 4dde7476..1eb231bd 100644 --- a/Assets.Scripts.Core.Scene/SceneController.cs +++ b/Assets.Scripts.Core.Scene/SceneController.cs @@ -1,3 +1,4 @@ +using Assets.Scripts.Core.Buriko; using Assets.Scripts.Core.AssetManagement; using MOD.Scripts.Core; using MOD.Scripts.Core.Scene; @@ -151,20 +152,37 @@ private void SetLayerActiveOnBothScenes(Layer layer) public void ControlMotionOfSprite(int layer, MtnCtrlElement[] motions, int style) { - Layer layer2 = GetLayer(layer); - layer2.ControlLayerMotion(motions); + Layer ifInUse = GetIfInUse(layer); + if (ifInUse == null) + { + Debug.LogWarning("Attempting to call ControlMotionOfSprite on layer " + layer + " but it is not active in the scene."); + } + else + { + ifInUse.ControlLayerMotion(motions); + } } public void MoveSprite(int layer, int x, int y, int z, int angle, int easetype, float alpha, float wait, bool isblocking) { - Layer layer2 = GetLayer(layer); - layer2.MoveLayer(x, y, z, alpha, easetype, wait, isblocking, adjustAlpha: true); - layer2.SetAngle((float)angle, wait); + Layer ifInUse = GetIfInUse(layer); + if (ifInUse == null) + { + Debug.LogWarning("Attempting to call MoveSprite on layer " + layer + " but it is not active in the scene."); + return; + } + ifInUse.MoveLayer(x, y, z, alpha, easetype, wait, isblocking, adjustAlpha: true); + ifInUse.SetAngle(angle, wait); } public void MoveSpriteEx(int layer, string filename, Vector3[] points, float alpha, float time, bool isblocking) { - Layer i = GetLayer(layer); + Layer i = GetIfInUse(layer); + if (i == null) + { + Debug.LogWarning("Attempting to call MoveSpriteEx on layer " + layer + " but it is not active in the scene."); + return; + } if (filename != string.Empty) { i.CrossfadeLayer(filename, time, isblocking); @@ -189,10 +207,17 @@ public void DrawBustshot(int layer, string textureName, int x, int y, int z, int gameSystem.RegisterAction(delegate { Layer layer2 = GetLayer(layer); + int iterationCount = 0; while (layer2.FadingOut) { layer2.HideLayer(); layer2 = GetLayer(layer); + iterationCount++; + if (iterationCount > 20) + { + Debug.LogWarning("We're trying to hide bustshot " + layer + " for DrawBustshot but for some reason it's stuck in a fading out state."); + break; + } } if (!move) { @@ -748,6 +773,10 @@ public void DeSerializeScene(MemoryStream ms) binaryReader.ReadSingle(); binaryReader.ReadInt32(); binaryReader.ReadInt32(); + if (BurikoScriptSystem.SaveVersion > 1) + { + binaryReader.ReadInt32(); + } DrawScene(backgroundfilename, 0.3f); if (binaryReader.ReadBoolean()) { @@ -757,6 +786,7 @@ public void DeSerializeScene(MemoryStream ms) binaryReader.ReadSingle(); binaryReader.ReadInt32(); binaryReader.ReadInt32(); + binaryReader.ReadInt32(); DrawFace(texture, 0f, isblocking: false); } for (int i = 0; i < 64; i++) @@ -773,13 +803,18 @@ public void DeSerializeScene(MemoryStream ms) float alpha = binaryReader.ReadSingle(); int num = binaryReader.ReadInt32(); int type = binaryReader.ReadInt32(); + int priority = i; + if (BurikoScriptSystem.SaveVersion > 1) + { + priority = binaryReader.ReadInt32(); + } if (i != 50) { bool isBustshot = num != 0; Layer layer = GetLayer(i); - UpdateLayerMask(layer, i); + UpdateLayerMask(layer, priority); layer.DrawLayer(textureName, (int)position.x, (int)position.y, 0, null, alpha, isBustshot, type, 0f, isBlocking: false); - layer.SetPriority(i); + layer.SetPriority(priority); layer.RestoreScaleAndPosition(scale, position); } } diff --git a/Assets.Scripts.UI.Config/ConfigManager.cs b/Assets.Scripts.UI.Config/ConfigManager.cs index 7f563131..10c02e09 100644 --- a/Assets.Scripts.UI.Config/ConfigManager.cs +++ b/Assets.Scripts.UI.Config/ConfigManager.cs @@ -1,5 +1,6 @@ using Assets.Scripts.Core; using System; +using MOD.Scripts.UI; using System.Collections; using UnityEngine; @@ -63,11 +64,18 @@ private IEnumerator DoOpen(int offscreen) GameSystem.Instance.MainUIController.FadeOut(0.3f, false); GameSystem.Instance.SceneController.HideFace(0.3f); GameSystem.Instance.ExecuteActions(); - if (GameSystem.Instance.ConfigMenuFontSize > 0) + RefreshFontSettings(); + } + + public void RefreshFontSettings() + { + if (GameSystem.Instance.ConfigMenuFontSize > 0 && panel != null) { foreach (TextRefresher text in Panel.GetComponentsInChildren()) { + text.SetFontWeight(MODFontAdjuster.GetNormalFontWeight()); text.SetFontSize(GameSystem.Instance.ConfigMenuFontSize); + text.SetFontOutlineWidth(GameSystem.Instance.OutlineWidth); } } yield break; diff --git a/Assets.Scripts.UI/MainUIController.cs b/Assets.Scripts.UI/MainUIController.cs index 6d5f7720..39de8aa4 100644 --- a/Assets.Scripts.UI/MainUIController.cs +++ b/Assets.Scripts.UI/MainUIController.cs @@ -778,5 +778,6 @@ private static void GUIUnclickableTextArea(Rect rect, string text) GUI.Label(rect, text, GUI.skin.textArea); } + } } diff --git a/MOD.Scripts.Core.Scene/MODLipsyncCache.cs b/MOD.Scripts.Core.Scene/MODLipsyncCache.cs index 540199fd..055c9ef8 100644 --- a/MOD.Scripts.Core.Scene/MODLipsyncCache.cs +++ b/MOD.Scripts.Core.Scene/MODLipsyncCache.cs @@ -40,6 +40,13 @@ public static bool GetLastDrawInformation(int character, out LastDrawInformation public static void SetLastDrawInformation(int character, int layer, string baseTextureName) { + // Ignore any 'null' texture and print error message + if(baseTextureName == null) + { + MODLogger.Log($"WARNING: LastDrawInformationManager.SetLastDrawInformation called with baseTextureName = null (character: {character} layer: {layer})", true); + return; + } + if (character < lastDrawInformation.Length) { lastDrawInformation[character] = new LastDrawInformation(layer, baseTextureName); @@ -218,6 +225,13 @@ public static bool LoadOrUseCache(Texture2D maybeBaseTexture, int character, out return false; } + // If the baseTextureName is null, we won't know what texture to load, so just give up + if(info.baseTextureName == null) + { + textureGroup = null; + return false; + } + if (cache.TryGetValue(info.baseTextureName, out TextureGroup cachedTextures)) { DebugLog($"LoadOrUseCache() - Cache hit on [{info.baseTextureName}]"); diff --git a/MOD.Scripts.UI/MODFontAdjuster.cs b/MOD.Scripts.UI/MODFontAdjuster.cs new file mode 100644 index 00000000..314d47c4 --- /dev/null +++ b/MOD.Scripts.UI/MODFontAdjuster.cs @@ -0,0 +1,88 @@ +using Assets.Scripts.Core; +using Assets.Scripts.UI; +using System; +using System.Collections.Generic; +using System.Text; +using UnityEngine; + +namespace MOD.Scripts.UI +{ + internal class MODFontAdjuster + { + private static void SetFontMaterialSetting(int settingID, float value) + { + GameSystem.Instance.MainUIController.TextWindow.fontSharedMaterial.SetFloat(settingID, value); + } + + private static float GetFontMaterialSetting(int settingID) + { + return GameSystem.Instance.MainUIController.TextWindow.fontSharedMaterial.GetFloat(settingID); + } + + /// + /// Sets the font outline width, and updates the current textwindow outline width + /// Hopefully if you toggle language (which toggles the font on chapters 1-9), the outline width is retained. + /// You will likely need to increase the font weight if you increase the outline width, as the outline 'eats' + /// into the characters, rather than expanding outwards. + /// + /// The outline width as a float typically between (0, 1) + public static void SetFontOutlineWidth(float outlineWidth) + { + GameSystem.Instance.OutlineWidth = outlineWidth; + GameSystem.Instance.MainUIController.TextWindow.outlineWidth = GameSystem.Instance.OutlineWidth; + } + + public static float GetNormalFontWeight() => GetFontMaterialSetting(TMPro.ShaderUtilities.ID_WeightNormal); + public static float GetBoldFontWeight() => GetFontMaterialSetting(TMPro.ShaderUtilities.ID_WeightBold); + + /// + /// Some chapters TextWindow don't let you set the font weight. For those chapters, the "_WeightNormal" + /// parameter on the material is set directly. + /// + /// The font weight, between -1 and 1 (more or less). + /// Negative numbers reduce the weight, positive numbers increase it. + public static void SetNormalFontWeight(float weight) + { + // Modifying fontSharedMaterial works, I guess doing so modifies all instances, + // while fontMaterial only modifies a single instance? + // See the docs: + // - http://digitalnativestudios.com/textmeshpro/docs/ScriptReference/TextMeshPro.html + // - http://digitalnativestudios.com/textmeshpro/docs/ScriptReference/TextMeshPro-fontSharedMaterial.html + SetFontMaterialSetting(TMPro.ShaderUtilities.ID_WeightNormal, weight); + } + + public static void SetBoldFontWeight(float weight) => SetFontMaterialSetting(TMPro.ShaderUtilities.ID_WeightBold, weight); + + public static void SetFaceDilation(float faceDilate) => SetFontMaterialSetting(TMPro.ShaderUtilities.ID_FaceDilate, faceDilate); + + public static float GetFaceDilation() => GetFontMaterialSetting(TMPro.ShaderUtilities.ID_FaceDilate); + + //private void SetFontMaterialSetting(int settingID, float value) + //{ + // FontMaterialSettingCache[settingID] = value; + // TextWindow.fontSharedMaterial.SetFloat(settingID, value); + //} + + //private float GetFontMaterialSetting(int settingID) + //{ + // return TextWindow.fontSharedMaterial.GetFloat(settingID); + //} + + //public static int ID_UnderlayOffsetX; + + //public static int ID_UnderlayOffsetY; + + //public static int ID_UnderlayDilate; + + //public static int ID_UnderlaySoftness; + + + // TODO: Also allow setting these values controlling drop shadow? + // For rei, the following values are used: + // _UnderlayDilate = 0.0900000036 + // _UnderlayOffsetX = 0.5 + // _UnderlayOffsetY = -0.5 + // _UnderlaySoftness = 0.312000006 + + } +} diff --git a/MOD.Scripts.UI/MODMenu.cs b/MOD.Scripts.UI/MODMenu.cs index 5be9a9ed..89ef93b4 100644 --- a/MOD.Scripts.UI/MODMenu.cs +++ b/MOD.Scripts.UI/MODMenu.cs @@ -30,6 +30,7 @@ public class MODMenu private readonly GameSystem gameSystem; public bool visible; public bool debug; + private bool lastDebug; private bool lastMenuVisibleStatus; private MODSimpleTimer defaultToolTipTimer; private MODSimpleTimer startupWatchdogTimer; @@ -44,6 +45,8 @@ public class MODMenu private MODMenuAudioSetup audioSetupMenu; private MODMenuModuleInterface currentMenu; // The menu that is currently visible + private MODMenuFontConfig fontMenuFragment; + string lastToolTip = String.Empty; string startupFailureToolTip = Loc.MODMenu_16; //It looks like there was a problem starting up\n\nPlease send the developers your log file (output_log.txt or Player.log).\n\nYou can try the following yourself to fix the issue.\n 1. Try waiting 30 seconds for the game to progress. If nothing happens, try restarting the game\n\n 2. Use the buttons under 'Troubleshooting' on the bottom left to show your save files, log files, and compiled scripts.\n\n 3. If the log indicates you have corrupt save files, you may wish to delete the offending save file (or all of them).\n\n 4. You can try to clear your compiled script files, then restart the game.\n\n 5. If the above do not fix the problem, please click the 'Open Support Page' button, which has extra troubleshooting info and links to join our Discord server for direct support. @@ -67,6 +70,7 @@ public MODMenu(GameSystem gameSystem) this.audioOptionsMenu = new MODMenuAudioOptions(this); this.normalMenu = new MODMenuNormal(this, this.audioOptionsMenu); this.audioSetupMenu = new MODMenuAudioSetup(this, this.audioOptionsMenu); + this.fontMenuFragment = new MODMenuFontConfig(); this.currentMenu = this.normalMenu; this.debugWindowRect = new Rect(0, 0, Screen.width / 3, Screen.height - 50); @@ -92,6 +96,12 @@ public void LateUpdate() } } + private void OnBeforeDebugMenuVisible() + { + fontMenuFragment.OnBeforeMenuVisible(); + } + + // This is a separate, smaller draggable mod menu, mainly for developer use. private void OnGUIDebugWindow(int windowID) { MODStyleManager styleManager = MODStyleManager.OnGUIInstance; @@ -100,15 +110,16 @@ private void OnGUIDebugWindow(int windowID) bool bgmFlagOK = MODAudioSet.Instance.GetBGMCascade(GetGlobal("GAltBGM"), out PathCascadeList BGMCascade); bool seFlagOK = MODAudioSet.Instance.GetSECascade(GetGlobal("GAltSE"), out PathCascadeList SECascade); + // ============================= Begin Sroll View ============================= if (!visible) { leftDebugColumnScrollPosition = GUILayout.BeginScrollView(leftDebugColumnScrollPosition, GUILayout.Width(Screen.width / 3), GUILayout.Height(Screen.height*9/10)); } - GUILayout.Label(Loc.MODMenu_0, styleManager.Group.upperLeftHeadingLabel); //[Audio Tracking] - indicates what would play on each BGM flow - GUILayout.Label($"{MODAudioTracking.Instance}", styleManager.Group.upperLeftHeadingLabel); + HeadingLabel(Loc.MODMenu_0); //[Audio Tracking] - indicates what would play on each BGM flow + Label($"{MODAudioTracking.Instance}"); - GUILayout.Label(Loc.MODMenu_1, styleManager.Group.upperLeftHeadingLabel); //[Audio Flags and last played audio] - GUILayout.Label($"Audio Set: {GetGlobal("GAudioSet")} ({MODAudioSet.Instance.GetCurrentAudioSetDisplayName()})\n\n" + + HeadingLabel(Loc.MODMenu_1); //[Audio Flags and last played audio] + Label($"Audio Set: {GetGlobal("GAudioSet")} ({MODAudioSet.Instance.GetCurrentAudioSetDisplayName()})\n\n" + $"AltBGM: {GetGlobal("GAltBGM")}\n" + $"AltBGMFlow: {GetGlobal("GAltBGMflow")} ({MODAudioSet.Instance.GetBGMFlowName(GetGlobal("GAltBGMflow"))})\n" + $"Last Played BGM: {AssetManager.Instance.debugLastBGM}\n" + @@ -122,16 +133,18 @@ private void OnGUIDebugWindow(int windowID) $"Last Played Voice Path: {AssetManager.Instance.debugLastVoice}\n" + $"Other Last Played Path: {AssetManager.Instance.debugLastOtherAudio}"); - GUILayout.Label(Core.Scene.MODLipsyncCache.DebugInfo()); + Label(Core.Scene.MODLipsyncCache.DebugInfo()); - if (debug) + // Button to reset GAudio Set + if(Button(new GUIContent(Loc.MODMenu_2, Loc.MODMenu_3))) //Reset GAudioSet | Set GAudioSet to 0, to force the game to do audio setup on next startup { - if(Button(new GUIContent(Loc.MODMenu_2, Loc.MODMenu_3))) //Reset GAudioSet | Set GAudioSet to 0, to force the game to do audio setup on next startup - { - SetGlobal("GAudioSet", 0); - } + SetGlobal("GAudioSet", 0); } + // Font Adjustment Debug Menu + fontMenuFragment.OnGUIFontDebug(); + + // Button to close the debug menu if (Button(new GUIContent(Loc.MODMenu_4, Loc.MODMenu_5))) //Close | Close the debug menu { ToggleDebugMenu(); @@ -141,6 +154,12 @@ private void OnGUIDebugWindow(int windowID) { GUILayout.EndScrollView(); } + // ============================= End Scroll View ============================= + + if(GameSystem.Instance.MODIgnoreInputs()) + { + Label("NOTE: Game Paused while Mouse On Debug Menu!"); + } GUI.DragWindow(new Rect(0, 0, 10000, 10000)); } @@ -223,10 +242,24 @@ public void OnGUIFragment() MODStyleManager styleManager = MODStyleManager.OnGUIInstance; buttonClickSound = GUISound.Click; + // If no menus are visible, allow mod inputs + if(!visible && !debug) + { + gameSystem.SetMODIgnoreInputs(false); + } + + if (debug && !lastDebug) + { + OnBeforeDebugMenuVisible(); + } if (debug && AssetManager.Instance != null) { debugWindowRect = GUILayout.Window(DEBUG_WINDOW_ID, debugWindowRect, OnGUIDebugWindow, Loc.MODMenu_6, styleManager.modMenuAreaStyleLight); //Developer Debug Window (click to drag) + + // Prevent mouse clicks being registered by the game when using debug menu + gameSystem.SetMODIgnoreInputs(debugWindowRect.Contains(Input.mousePosition)); } + lastDebug = debug; GUI.depth = 0; diff --git a/MOD.Scripts.UI/MODMenuCommon.cs b/MOD.Scripts.UI/MODMenuCommon.cs index 5cbb5881..3d51d30d 100644 --- a/MOD.Scripts.UI/MODMenuCommon.cs +++ b/MOD.Scripts.UI/MODMenuCommon.cs @@ -72,7 +72,41 @@ public static string TextField(string text, int maxLength, params GUILayoutOptio return GUILayout.TextField(text, maxLength, MODStyleManager.OnGUIInstance.Group.textField, options); } + public static string TextField(string text, bool blankSkipChanged, out bool hasChanged, params GUILayoutOption[] options) + { + string newValue = GUILayout.TextField(text, MODStyleManager.OnGUIInstance.Group.textField, options); + + if(blankSkipChanged && newValue.Trim() == String.Empty) + { + hasChanged = false; + return newValue; + } + + hasChanged = text != newValue; + return newValue; + } + + public static string TextArea(string text, int maxHeight) + { + return GUILayout.TextArea(text, MODStyleManager.OnGUIInstance.Group.textField, new GUILayoutOption[] { + GUILayout.ExpandHeight(true), + GUILayout.MaxHeight(maxHeight) + }); + } + public static int GetGlobal(string flagName) => BurikoMemory.Instance.GetGlobalFlag(flagName).IntValue(); public static void SetGlobal(string flagName, int flagValue) => BurikoMemory.Instance.SetGlobalFlag(flagName, flagValue); + public static bool TrySetGlobal(string flagName, int flagValue) + { + if(BurikoMemory.Instance.IsFlag(flagName)) + { + SetGlobal(flagName, flagValue); + return true; + } + else + { + return false; + } + } } } diff --git a/MOD.Scripts.UI/MODMenuFontConfig.cs b/MOD.Scripts.UI/MODMenuFontConfig.cs new file mode 100644 index 00000000..1f379704 --- /dev/null +++ b/MOD.Scripts.UI/MODMenuFontConfig.cs @@ -0,0 +1,117 @@ + +using Assets.Scripts.Core; +using System; +using UnityEngine; +using static MOD.Scripts.UI.MODMenuCommon; + +namespace MOD.Scripts.UI +{ + class MODMenuFontConfig + { + string TextField_FontOutlineWidth; + string TextField_NormalFontWeight; + string TextField_BoldFontWeight; + string TextField_FontSize; + string TextField_ConfigMenuFontSize; + string TextField_FaceDilation; + + string TextArea_GeneratedScriptFragment = ""; + + public void OnBeforeMenuVisible() { + TextField_FontOutlineWidth = asPercent(GameSystem.Instance.OutlineWidth).ToString(); + TextField_NormalFontWeight = asPercent(MODFontAdjuster.GetNormalFontWeight()).ToString(); + TextField_BoldFontWeight = asPercent(MODFontAdjuster.GetBoldFontWeight()).ToString(); + TextField_FontSize = GameSystem.Instance.MainUIController.TextWindow.fontSize.ToString(); + TextField_ConfigMenuFontSize = GameSystem.Instance.ConfigMenuFontSize.ToString(); + TextField_FaceDilation = asPercent(MODFontAdjuster.GetFaceDilation()).ToString(); + + UpdateGeneratedScriptFragment(); + } + + public void OnGUIFontDebug() + { + Label("Font Debugging"); + + // --------- Font Outline and Size Adjustment --------- + GUILayout.BeginHorizontal(); + + Label(new GUIContent("Face Dilate (%)", "Face Dilation\n\nExpands or shrinks the text thickness.\n\nTry adjusting this rather than font weight.")); + TextField_FaceDilation = TextField(TextField_FaceDilation, true, out bool faceDilationHasChanged); + + Label(new GUIContent("Outline (%)", "Main Text Window Font Outline Width")); + TextField_FontOutlineWidth = TextField(TextField_FontOutlineWidth, true, out bool outlineHasChanged); + + GUILayout.EndHorizontal(); + + // --------- Font Size Adjustment --------- + GUILayout.BeginHorizontal(); + + Label(new GUIContent("Font Size", "Main Text Window Font Size")); + TextField_FontSize = TextField(TextField_FontSize, true, out bool fontSizeHasChanged); + + Label(new GUIContent("Config Font Size", "Config Menu Font Size")); + TextField_ConfigMenuFontSize = TextField(TextField_ConfigMenuFontSize, true, out bool configFontSizeHasChanged); + + GUILayout.EndHorizontal(); + + // --------- Font Weight Adjustment --------- + Label("!Note: Adjust face dilation instead of these values!"); + + GUILayout.BeginHorizontal(); + + Label(new GUIContent("!Normal Weight (% change)!", "Main Text Window Normal Font Weight")); + TextField_NormalFontWeight = TextField(TextField_NormalFontWeight, true, out bool fontWeightHasChanged); + + Label(new GUIContent("!Bold Weight (% change)!", "Main Text Window Bold Font Weight")); + TextField_BoldFontWeight = TextField(TextField_BoldFontWeight, true, out bool fontBoldWeightHasChanged); + + GUILayout.EndHorizontal(); + + // --------- Textbox showing example code --------- + TextArea(TextArea_GeneratedScriptFragment, Screen.height / 8); + + if (outlineHasChanged || + fontWeightHasChanged || + fontBoldWeightHasChanged || + fontSizeHasChanged || + configFontSizeHasChanged || + faceDilationHasChanged) + { + try + { + // Update main text window font + MODFontAdjuster.SetFontOutlineWidth(fromPercent(TextField_FontOutlineWidth)); + MODFontAdjuster.SetNormalFontWeight(fromPercent(TextField_NormalFontWeight)); + MODFontAdjuster.SetBoldFontWeight(fromPercent(TextField_BoldFontWeight)); + GameSystem.Instance.MainUIController.SetFontSize(int.Parse(TextField_FontSize)); // SetFontSize already takes an percentage as int + MODFontAdjuster.SetFaceDilation(fromPercent(TextField_FaceDilation)); + + // Update config menu font + GameSystem.Instance.ConfigMenuFontSize = int.Parse(TextField_ConfigMenuFontSize); + + // Refresh the config menu only if it is open + GameSystem.Instance.ConfigManager()?.RefreshFontSettings(); + + UpdateGeneratedScriptFragment(); + } + catch (Exception e) + { + MODToaster.Show("Failed to set font settings:" + e.Message); + } + } + } + + private void UpdateGeneratedScriptFragment() + { + TextArea_GeneratedScriptFragment = $"//Font Size: [{TextField_FontSize}] - Please update init.txt accordingly\n" + + $"ModSetConfigFontSize({TextField_ConfigMenuFontSize});\n" + + $"ModSetMainFontOutlineWidth({TextField_FontOutlineWidth});\n" + + $"ModGenericCall(\"NormalFontWeight\", \"{TextField_NormalFontWeight}\");\n" + + $"ModGenericCall(\"BoldFontWeight\", \"{TextField_BoldFontWeight}\");\n" + + $"ModGenericCall(\"FaceDilate\", \"{TextField_FaceDilation}\");\n"; + } + + public int asPercent(float fontOption) => Mathf.RoundToInt(fontOption * 100); + public float fromPercent(string fontOption) => (float)(float.Parse(fontOption) / 100.0f); + } +} diff --git a/MOD.Scripts.UI/MODMenuNormal.cs b/MOD.Scripts.UI/MODMenuNormal.cs index 2a765561..09efec65 100644 --- a/MOD.Scripts.UI/MODMenuNormal.cs +++ b/MOD.Scripts.UI/MODMenuNormal.cs @@ -311,7 +311,7 @@ private static void ShowExperimentalGameplayTools() else { string clearStateIndicator = gameClear ? Loc.MODMenuNormal_87 : Loc.MODMenuNormal_88; //Reset All Progress | Force Game Clear - gameClearButtonText = clearStateIndicator + "(" + Loc.MODMenuNormal_89 + $"{gameClearClickCount}" + Loc.MODMenuNormal_90 + ")"; //Click | more times + gameClearButtonText = clearStateIndicator + " (" + Loc.MODMenuNormal_89 + $" {gameClearClickCount} " + Loc.MODMenuNormal_90 + ")"; //Click | more times } string gameClearButtonDescription = @@ -321,15 +321,53 @@ private static void ShowExperimentalGameplayTools() { if (gameClearClickCount == 1) { + // Some flags might not be available on all chapters, but try to set them anyway if (gameClear) { - SetGlobal("GFlag_GameClear", 0); - SetGlobal("GHighestChapter", 0); + TrySetGlobal("GFlag_GameClear", 0); + TrySetGlobal("GHighestChapter", 0); + + // Rei + TrySetGlobal("GOmakeUnlock", 0); + TrySetGlobal("GCastReview", 0); + TrySetGlobal("GSaikoroshi", 0); + TrySetGlobal("GHirukowashi", 0); + TrySetGlobal("GBatsukoishi", 0); + + // Hou+ + TrySetGlobal("TEIEND", 1); + TrySetGlobal("HIGUEND", 1); + TrySetGlobal("MEHEND", 1); + // Hou+: Get an achievement once you've read all 9 staff rooms + for (int i = 1; i <= 9; i++) + { + TrySetGlobal($"ReadStaffRoom{i}", 0); + } } else { - SetGlobal("GFlag_GameClear", 1); - SetGlobal("GHighestChapter", 999); + TrySetGlobal("GFlag_GameClear", 1); + TrySetGlobal("GHighestChapter", 999); + + // Rei + TrySetGlobal("GOmakeUnlock", 1); + TrySetGlobal("GCastReview", 1); + TrySetGlobal("GSaikoroshi", 1); + TrySetGlobal("GHirukowashi", 1); + TrySetGlobal("GBatsukoishi", 1); + + // Hou+ + TrySetGlobal("TEIEND", 1); + TrySetGlobal("HIGUEND", 1); + TrySetGlobal("MEHEND", 1); + // Hou+: Get an achievement once you've read all 9 staff rooms + for (int i = 1; i <= 9; i++) + { + TrySetGlobal($"ReadStaffRoom{i}", 1); + } + + + } } @@ -372,6 +410,12 @@ private void TroubleShootingTabOnGUI() GUILayout.EndHorizontal(); OnGUIComputedLipsync(); + + Label("Font Debugging"); + if (Button(new GUIContent("Font Debug is on the Draggable Debug Menu", "The font debug settings are on the draggable debug menu, to avoid it blocking the screen while you see the fonts change."))) + { + modMenu.ToggleDebugMenu(); + } } else { diff --git a/README.md b/README.md index 68b62dfa..7b4c9958 100644 --- a/README.md +++ b/README.md @@ -99,9 +99,13 @@ Use the `-to` command to process just part of the video for testing. For example ### Building on Windows -* These projects (`Assembly-CSharp.csproj`) have been built successfully with Visual Studio Community 2017 v15.7.5 and msbuild v15.7.180.61344, though in theory any compiler supporting C# 7.1 should suffice. +* These projects (`Assembly-CSharp.csproj`) have been built successfully with: + - Visual Studio Community 2017 v15.7.5 and msbuild v15.7.180.61344, though in theory any compiler supporting C# 7.1 should suffice. + - Microsoft Visual Studio Community 2022 (64-bit) v17.7.5 * To build with Visual Studio, load the sln file and use build command. +Let us know if you have issues building the project. + ### Building on Linux * On Linux, you can use Mono to build the DLL using the `msbuild` command (see below)(just run `msbuild /p:Configuration=Release`) @@ -142,3 +146,13 @@ The DLL will be located in the `HigurashiEp[EPISODE_NUMBER]_Data\Managed\Assembl | matsuri-mod |[Ch.8 Matsuribayashi](https://github.com/07th-mod/matsuribayashi) | | | rei-mod |[Ch.9 Rei](https://github.com/07th-mod/higurashi-rei) | Uses new Unity 2019.4.X | | console-arcs |[Console Arcs](https://github.com/07th-mod/higurashi-console-arcs ) | Based on Ch.4 Himatsubishi DLL | + +## Visual Studio issues + +### ProjectGUID Changes when reloading project, then building + +If you change branches, Visual Studio will ask you to 'reload the project'. If you then build the project, the `` might change (in `Assembly-CSharp.csproj`). + +This only happens when reloading the project - if you close the project, change branch, then open it again, it won't change the GUID. + +You can keep using the 'reload the project' feature, just don't commit the updated GUID (however, if you modify the GUID accidentally, it has no effect) diff --git a/TextRefresher.cs b/TextRefresher.cs index a40c6683..8ab114a8 100644 --- a/TextRefresher.cs +++ b/TextRefresher.cs @@ -72,4 +72,20 @@ public void SetFontSize(float size) if (textMesh == null) { return; } textMesh.fontSize = size; } + + // See MainUIController for detailed comments on this + public void SetFontWeight(float weight) + { + textMesh.fontSharedMaterial.SetFloat(TMPro.ShaderUtilities.ID_WeightNormal, weight); + } + + public void SetFontOutlineWidth(float outlineWidth) + { + // Unsure why, but setting the outline width via the property "textMesh.outlineWidth" causes + // the config menu text to disappear entirely, no matter what setting you use, even though + // when using that same property for the main text window works fine. + // + // Setting the value in the shader directly seems to work. + textMesh.fontSharedMaterial.SetFloat(TMPro.ShaderUtilities.ID_OutlineWidth, outlineWidth); + } } diff --git a/tools/localization.json b/tools/localization.json index 19053a92..021a6f83 100644 --- a/tools/localization.json +++ b/tools/localization.json @@ -11,7 +11,9 @@ "ExampleEntry": { "text": "This text will displayed by default.", "textJP": "This text will be displayed when the language is changed to Japanese in-game.", - "comment": "You can store comments here. Additionally, if any field is left empty and there is no hard-coded fallback, it will display as #NOT SET#" + "comment": "You can store comments here. Additionally, if any field is left empty and there is no hard-coded fallback, it will display as #NOT SET#", + "info_1": "Please read https://07th-mod.com/wiki/developer/translation/introduction/#localizing-mod-menu before attempting to localize the mod menu! Some mod menu strings are not stored in this file!", + "info_2": "Please place this 'localization.json' file in the HigurashiEp0X_Data folder (eg for Ch.1, place it at 'HigurashiEp01_Data/localization.json')" }, "MODMenu_0": { "comment": "The below entries are for the F10 mod menu, in the file MOD.Scripts.UI/MODMenu.cs. NOTE: some of these are the debug menu strings, wich the user will never use or see.",