diff --git a/Winch.Examples/ExampleItems/Assets/Boat/Flags/exampleitems.flag.json b/Winch.Examples/ExampleItems/Assets/Boat/Flags/exampleitems.flag.json new file mode 100644 index 00000000..1b685bc8 --- /dev/null +++ b/Winch.Examples/ExampleItems/Assets/Boat/Flags/exampleitems.flag.json @@ -0,0 +1,6 @@ +{ + "flagItem": "exampleitems.flag", + "flagTexture": "FlagMaterialTemplate", + "localizedNameKey": "exampleitems.flag.option" +} + diff --git a/Winch.Examples/ExampleItems/Assets/Boat/Paints/exampleitems.color.json b/Winch.Examples/ExampleItems/Assets/Boat/Paints/exampleitems.color.json new file mode 100644 index 00000000..dd5ceb09 --- /dev/null +++ b/Winch.Examples/ExampleItems/Assets/Boat/Paints/exampleitems.color.json @@ -0,0 +1,11 @@ +{ + "color": { + "r": 255, + "g": 150, + "b": 150, + "a": 255 + }, + "localizedNameKey": "exampleitems.color.option", + "questGridConfig": "exampleitems.color.crabs" +} + diff --git a/Winch.Examples/ExampleItems/Assets/Dialogues/CollectorHeartOfTheSeaDialogue.yarn b/Winch.Examples/ExampleItems/Assets/Dialogues/CollectorHeartOfTheSeaDialogue.yarn index d35e743c..4c6368b3 100644 --- a/Winch.Examples/ExampleItems/Assets/Dialogues/CollectorHeartOfTheSeaDialogue.yarn +++ b/Winch.Examples/ExampleItems/Assets/Dialogues/CollectorHeartOfTheSeaDialogue.yarn @@ -12,7 +12,7 @@ COLLECTOR_NAME_KEY: Oh? What is that you have in your hand? #chuckle #line:examp <> -> I have absolutely no idea #line:exampleitems.collector.noidea <> -<> +<> COLLECTOR_NAME_KEY: It looks like a sphere but it is blocky. #line:exampleitems.collector.blockysphere <> COLLECTOR_NAME_KEY: I wonder what "heart" means. #grunt #line:exampleitems.collector.wonder diff --git a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.color.crabs.json b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.color.crabs.json new file mode 100644 index 00000000..f0cfdbe0 --- /dev/null +++ b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.color.crabs.json @@ -0,0 +1,20 @@ +{ + "columns": 3, + "rows": 2, + "cellGroupConfigs": [ + { + "cells": [], + "itemType": "NONE", + "itemSubtype": "NONE", + "isHidden": true, + "damageImmune": true + } + ], + "mainItemData": "exampleitems.rainbowfiddlercrab", + "mainItemType": "GENERAL", + "mainItemSubtype": "FISH", + "itemsInThisBelongToPlayer": false, + "canAddItemsInQuestMode": true, + "hasUnderlay": false, + "gridKey": "EXAMPLE_COLOR_CRABS" +} \ No newline at end of file diff --git a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.input.json b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.input.json index 0225a677..0e834982 100644 --- a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.input.json +++ b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.input.json @@ -1,6 +1,15 @@ { "columns": 4, "rows": 2, + "cellGroupConfigs": [ + { + "cells": [], + "itemType": "NONE", + "itemSubtype": "NONE", + "isHidden": true, + "damageImmune": true + } + ], "mainItemData": "exampleitems.diamond", "mainItemType": "GENERAL", "mainItemSubtype": "TRINKET", diff --git a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.output.json b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.output.json index 37dfb392..7458fb73 100644 --- a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.output.json +++ b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.output.json @@ -1,6 +1,15 @@ { "columns": 1, "rows": 1, + "cellGroupConfigs": [ + { + "cells": [], + "itemType": "NONE", + "itemSubtype": "NONE", + "isHidden": true, + "damageImmune": true + } + ], "mainItemData": "exampleitems.milk", "mainItemType": "GENERAL", "mainItemSubtype": "GENERAL", diff --git a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.recipe.json b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.recipe.json index 4815a110..52a10062 100644 --- a/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.recipe.json +++ b/Winch.Examples/ExampleItems/Assets/GridConfigs/exampleitems.recipe.json @@ -1,6 +1,15 @@ { "columns": 4, "rows": 2, + "cellGroupConfigs": [ + { + "cells": [], + "itemType": "NONE", + "itemSubtype": "NONE", + "isHidden": true, + "damageImmune": true + } + ], "mainItemData": "exampleitems.diamond", "mainItemType": "GENERAL", "mainItemSubtype": "TRINKET", diff --git a/Winch.Examples/ExampleItems/Assets/Localization/en.json b/Winch.Examples/ExampleItems/Assets/Localization/en.json index e06a8441..f373c67b 100644 --- a/Winch.Examples/ExampleItems/Assets/Localization/en.json +++ b/Winch.Examples/ExampleItems/Assets/Localization/en.json @@ -89,6 +89,11 @@ "exampleitems.recipe.name": "Recipe Name", "exampleitems.recipe.description": "Recipe Description", + "exampleitems.flag.name": "White Flag", + "exampleitems.flag.desc": "A flag with nothing on it.", + "exampleitems.flag.option": "White flag.", + "exampleitems.color.option": "Salmon Pink.", + "exampleconfig.input": "Input", "exampleconfig.output": "Output", diff --git a/Winch.Examples/ExampleItems/Assets/POI/Harvest/exampleitems.exampleflagpoi.json b/Winch.Examples/ExampleItems/Assets/POI/Harvest/exampleitems.exampleflagpoi.json new file mode 100644 index 00000000..a4fc3574 --- /dev/null +++ b/Winch.Examples/ExampleItems/Assets/POI/Harvest/exampleitems.exampleflagpoi.json @@ -0,0 +1,13 @@ +{ + "location": { + "x": 400.0, + "y": 0.0, + "z": -290.0 + }, + "harvestableParticlePrefab": "ImportantDredgeParticles", + "items": [ "exampleitems.flag" ], + "startStock": 1, + "maxStock": 1, + "doesRestock": false, + "usesTimeSpecificStock": false +} diff --git a/Winch.Examples/ExampleItems/Assets/Quests/GridConfigs/exampleitems.color.crabs.json b/Winch.Examples/ExampleItems/Assets/Quests/GridConfigs/exampleitems.color.crabs.json new file mode 100644 index 00000000..fe5fd8bd --- /dev/null +++ b/Winch.Examples/ExampleItems/Assets/Quests/GridConfigs/exampleitems.color.crabs.json @@ -0,0 +1,30 @@ +{ + "titleString": "quest-grid.deliver-crabs", + "isSaved": true, + "allowManualExit": true, + "allowStorageAccess": true, + "gridConfiguration": "exampleitems.color.crabs", + "gridKey": "EXAMPLE_COLOR_CRABS", + "overrideGridCellColor": true, + "gridCellColor": "CRITICAL", + "presetGrid": { + "spatialItems": [ + { + "id": "exampleitems.rainbowfiddlercrab", + "x": 0, + "y": 0, + "z": 0 + } + ] + }, + "presetGridMode": "SILHOUETTE", + "questGridExitMode": "REVISITABLE", + "startingDurabilityProportion": 1.0, + "completeConditions": [ + { + "type": "ItemCount", + "item": "exampleitems.rainbowfiddlercrab", + "count": 1 + } + ] +} \ No newline at end of file diff --git a/Winch.Examples/ExampleItems/ExampleEnums.cs b/Winch.Examples/ExampleItems/ExampleEnums.cs index f45586d5..9fa11f8d 100644 --- a/Winch.Examples/ExampleItems/ExampleEnums.cs +++ b/Winch.Examples/ExampleItems/ExampleEnums.cs @@ -5,8 +5,18 @@ namespace ExampleItems; [EnumHolder] public static class ExampleEnums { - public static readonly ItemSubtype EXAMPLE; - public static readonly GridKey EXAMPLE_INPUT; - public static readonly GridKey EXAMPLE_OUTPUT; - public static readonly GridKey EXAMPLE_RECIPE; + [EnumHolder] + public static class ItemSubtypes + { + public static readonly ItemSubtype EXAMPLE; + } + + [EnumHolder] + public static class GridKeys + { + public static readonly GridKey EXAMPLE_INPUT; + public static readonly GridKey EXAMPLE_OUTPUT; + public static readonly GridKey EXAMPLE_RECIPE; + public static readonly GridKey EXAMPLE_COLOR_CRABS; + } } diff --git a/Winch/Assets/Dialogues/PainterOverride.yarn b/Winch/Assets/Dialogues/PainterOverride.yarn new file mode 100644 index 00000000..7ca98956 --- /dev/null +++ b/Winch/Assets/Dialogues/PainterOverride.yarn @@ -0,0 +1,149 @@ +title: Painter_Customize +--- +<> +<> +<> +<> +PAINTER_NAME_KEY: What can I help you with today? #lastline #line:0c88abb +<> + -> Deliver Flag. <> #repeat #quest #line:05e56b6 + <> + -> Deliver Flag. <> #repeat #line:059dc76 + <> + -> Paint boat. #repeat #line:00c5c0a + <> + -> Change flag. #repeat #line:082a9c7 + <> + -> Adjust bunting. #repeat #line:0fd9656 + <> + -> What do you do here? #line:0b2844b + <> + -> \\[Leave.\\] #exit #line:0969466 +=== +title: Painter_Customize_Bunting_Selected +--- +<> +<> + <> +<> + <> +<> +<> +PAINTER_NAME_KEY: As you wish... #mm #line:09dffaf +<> +=== +title: Painter_Customize_Color_Incomplete +--- +<> +<> +PAINTER_NAME_KEY: I don't have the right pigment to make that color. You'll need to bring me these [C3]crabs[/C3]: #sigh #line:08add0d +<> +<> + PAINTER_NAME_KEY: That should be all we need...let me grind them together... #line:03c9fd7 + <> + <> + <> +<> + <> + PAINTER_NAME_KEY: A different color, perhaps? #hmm #line:03949a5 + <> +<> +=== +title: Painter_Deliver_Flag_Success +--- +<> +PAINTER_NAME_KEY: So, you've found a scrap of fabric eh? Let me see... #hmm #line:0a67ffb +<> +<> +<> +PAINTER_NAME_KEY: A unique design. Do you want to attach it now? #lastline #line:0d160cf + -> Yes. #line:0fc6f52 + <> + <> + -> No. #line:075f7ba + <> + +=== +title: Painter_Deliver_Flag_Fail +--- +PAINTER_NAME_KEY: You don't seem to have any new flags with you. Come back when you find some. #annoyed #line:078f808 +<> + PAINTER_NAME_KEY: Have you tried searching to the [C0]North[/C0] of [C0]The Marrows[/C0]? #hmm #line:04c240d +<> + PAINTER_NAME_KEY: Have you tried searching to the [C0]South[/C0] of [C0]The Marrows[/C0]? #hmm #line:08f58e6 +<> + PAINTER_NAME_KEY: Have you tried searching around [C0]Gale Cliffs[/C0]? #hmm #line:08a461c +<> + PAINTER_NAME_KEY: Have you tried searching around [C0]Stellar Basin[/C0]? #hmm #line:03c25cd +<> + PAINTER_NAME_KEY: Have you tried searching around [C0]Twisted Strand[/C0]? #hmm #line:0554f08 +<> + PAINTER_NAME_KEY: Have you tried searching around [C0]Devil's Spine[/C0]? #hmm #line:02765dd +<> + PAINTER_NAME_KEY: Although...you already have so many - I'm not sure there are any more out there... #hmm #line:032c7ba +<> +<> +=== +title: Painter_Customize_FlagModded +--- +<> +<> +<> +<> +<> +<> + -> \\[Previous page.\\] #repeat #line:0509ef6 + <> + -> \\[Next page.\\] <> #repeat #line:00f9f4c + <> + -> \\[Back.\\] #exit #line:0e2c03d + <> + <> +=== +title: Painter_Customize_FlagModded_Previous +--- +<> + <> +<> + <> + <> +<> +=== +title: Painter_Customize_FlagModded_Next +--- +<> +<> +=== +title: Painter_Customize_Color_Page_Modded +--- +<> +<> +<> +<> +<> +<> + -> \\[Previous page.\\] #repeat #line:062a122 + <> + -> \\[Next page.\\] <> #repeat #line:01b7c6c + <> + -> \\[Back.\\] #exit #line:03f37d3 + <> + <> +=== +title: Painter_Customize_Color_Page_Modded_Previous +--- +<> + <> + <> +<> + <> + <> + <> +<> +=== +title: Painter_Customize_Color_Page_Modded_Next +--- +<> +<> +<> +=== \ No newline at end of file diff --git a/Winch/Core/API/DredgeEvent.cs b/Winch/Core/API/DredgeEvent.cs index bc36d281..783ab78b 100644 --- a/Winch/Core/API/DredgeEvent.cs +++ b/Winch/Core/API/DredgeEvent.cs @@ -60,4 +60,18 @@ public static void TriggerFishCaught(SpatialItemInstance itemInstance) WinchCore.Log.Debug($"Triggered OnFishCaught({itemInstance.id}) event"); OnFishCaught?.Invoke(itemInstance); } + + public static event Action OnBoatColorsChanged; + public static void TriggerBoatColorsChanged(BoatArea area, string paintId) + { + WinchCore.Log.Debug($"Triggered OnBoatColorsChanged({area},{paintId}) event"); + OnBoatColorsChanged?.Invoke(area, paintId); + } + + public static event Action OnBoatFlagChanged; + public static void TriggerBoatFlagChanged(string flagId) + { + WinchCore.Log.Debug($"Triggered OnBoatFlagChanged({flagId}) event"); + OnBoatFlagChanged?.Invoke(flagId); + } } diff --git a/Winch/Core/AssetLoader.cs b/Winch/Core/AssetLoader.cs index c8b5c49a..8f16aded 100644 --- a/Winch/Core/AssetLoader.cs +++ b/Winch/Core/AssetLoader.cs @@ -32,6 +32,7 @@ internal static void LoadAssets() WorldEventUtil.Initialize(); MapMarkerUtil.Initialize(); QuestUtil.Initialize(); + BoatUtil.Initialize(); } catch (Exception ex) { @@ -53,6 +54,15 @@ internal static void LoadAssets() } ModAssemblyLoader.ClearModContext(); } + + try + { + BoatUtil.PostInitialize(); + } + catch (Exception ex) + { + WinchCore.Log.Error($"Failed to post initialize winch utils: {ex}"); + } } private static void LoadAssetFolder(string path) @@ -79,6 +89,9 @@ private static void LoadAssetFolder(string path) string recipeFolderpath = Path.Combine(path, "Recipes"); string dialogueFolderpath = Path.Combine(path, "Dialogues"); string characterFolderpath = Path.Combine(path, "Characters"); + string boatFolderpath = Path.Combine(path, "Boat"); + string paintFolderpath = Path.Combine(boatFolderpath, "Paints"); + string flagFolderpath = Path.Combine(boatFolderpath, "Flags"); if(Directory.Exists(bundlesFolderpath)) LoadAssetBundleFiles(bundlesFolderpath); if(Directory.Exists(localizationFolderPath)) LoadLocalizationFiles(localizationFolderPath); @@ -102,6 +115,8 @@ private static void LoadAssetFolder(string path) if(Directory.Exists(recipeFolderpath)) LoadRecipeFiles(recipeFolderpath); if(Directory.Exists(dialogueFolderpath)) LoadDialogueFiles(dialogueFolderpath); if(Directory.Exists(characterFolderpath)) LoadCharacterFiles(characterFolderpath); + if(Directory.Exists(paintFolderpath)) LoadBoatPaintFiles(paintFolderpath); + if(Directory.Exists(flagFolderpath)) LoadBoatFlagFiles(flagFolderpath); } private static void LoadAssetBundleFiles(string bundlesFolderpath) @@ -586,4 +601,36 @@ private static void LoadCharacterFiles(string charactersFolderPath) } } } + + private static void LoadBoatPaintFiles(string paintFolderpath) + { + string[] paintFiles = Directory.GetFiles(paintFolderpath); + foreach (string paintFile in paintFiles) + { + try + { + BoatUtil.AddBoatPaintDataFromMeta(paintFile); + } + catch (Exception ex) + { + WinchCore.Log.Error($"Failed to load boat paint data from {paintFile}: {ex}"); + } + } + } + + private static void LoadBoatFlagFiles(string flagFolderpath) + { + string[] flagFiles = Directory.GetFiles(flagFolderpath); + foreach (string flagFile in flagFiles) + { + try + { + BoatUtil.AddBoatFlagDataFromMeta(flagFile); + } + catch (Exception ex) + { + WinchCore.Log.Error($"Failed to load boat flag data from {flagFile}: {ex}"); + } + } + } } diff --git a/Winch/Data/Boat/BoatBuntingData.cs b/Winch/Data/Boat/BoatBuntingData.cs deleted file mode 100644 index 22d01ed2..00000000 --- a/Winch/Data/Boat/BoatBuntingData.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Sirenix.OdinInspector; - -namespace Winch.Data.Boat; - -public class BoatBuntingData : SerializedScriptableObject -{ -} diff --git a/Winch/Data/Boat/BoatColorData.cs b/Winch/Data/Boat/BoatColorData.cs deleted file mode 100644 index f0fdb66e..00000000 --- a/Winch/Data/Boat/BoatColorData.cs +++ /dev/null @@ -1,7 +0,0 @@ -using Sirenix.OdinInspector; - -namespace Winch.Data.Boat; - -public class BoatColorData : SerializedScriptableObject -{ -} diff --git a/Winch/Data/Boat/BoatFlagData.cs b/Winch/Data/Boat/BoatFlagData.cs index e4ee9751..6332c7b6 100644 --- a/Winch/Data/Boat/BoatFlagData.cs +++ b/Winch/Data/Boat/BoatFlagData.cs @@ -7,11 +7,17 @@ namespace Winch.Data.Boat; public class BoatFlagData : SerializedScriptableObject { + [SerializeField] + public string id = string.Empty; + [SerializeField] public string flagItem = string.Empty; - public FlagItemData FlagItem => ItemUtil.GetFlagItemData(flagItem) as FlagItemData; + public virtual HarvestableItemData FlagItem => ItemUtil.GetFlagItemData(flagItem); [SerializeField] public Texture2D flagTexture = TextureUtil.GetTexture("FlagMaterialTemplate"); - public Material FlagMaterial => AssetBundleUtil.CreateLitCutoutMaterial(flagTexture.name, flagTexture); + public virtual Material FlagMaterial => AssetBundleUtil.CreateLitCutoutMaterial(flagTexture.name, flagTexture); + + [SerializeField] + public string localizedNameKey = null; } diff --git a/Winch/Data/Boat/BoatPaintData.cs b/Winch/Data/Boat/BoatPaintData.cs new file mode 100644 index 00000000..404f8772 --- /dev/null +++ b/Winch/Data/Boat/BoatPaintData.cs @@ -0,0 +1,21 @@ +using Sirenix.OdinInspector; +using UnityEngine; +using Winch.Util; + +namespace Winch.Data.Boat; + +public class BoatPaintData : SerializedScriptableObject +{ + [SerializeField] + public string id = string.Empty; + + [SerializeField] + public Color color = Color.white; + + [SerializeField] + public string localizedNameKey = null; + + [SerializeField] + public string questGridConfig = null; + public virtual QuestGridConfig QuestGridConfig => QuestUtil.GetQuestGridConfig(questGridConfig); +} diff --git a/Winch/Data/Boat/VanillaBoatFlagData.cs b/Winch/Data/Boat/VanillaBoatFlagData.cs new file mode 100644 index 00000000..fa49bbb5 --- /dev/null +++ b/Winch/Data/Boat/VanillaBoatFlagData.cs @@ -0,0 +1,40 @@ +using System.Linq; +using UnityEngine; +using Winch.Data.Item; +using Winch.Util; + +namespace Winch.Data.Boat; + +internal class VanillaBoatFlagData : BoatFlagData +{ + private int index = -1; + public int Index + { + get => index; + set + { + index = value; + id = value.ToString(); + flagItem = $"flag-{value}"; + flagMaterialName = $"Flag{value}_Mat"; + name = flagItem; + } + } + + private string flagMaterialName = "Flag1_Mat"; + private Material flagMaterial; + public override Material FlagMaterial + { + get + { + if (flagMaterial == null && !string.IsNullOrWhiteSpace(flagMaterialName)) + { + flagMaterial = Resources.FindObjectsOfTypeAll() + .FirstOrDefault(mat => mat.name == flagMaterialName); + + if (flagMaterial != null) flagTexture = flagMaterial.GetTextureFromDescription("Albedo") as Texture2D; + } + return flagMaterial; + } + } +} diff --git a/Winch/Data/Boat/VanillaBoatPaintData.cs b/Winch/Data/Boat/VanillaBoatPaintData.cs new file mode 100644 index 00000000..9e3454d0 --- /dev/null +++ b/Winch/Data/Boat/VanillaBoatPaintData.cs @@ -0,0 +1,21 @@ +using CommandTerminal; +using UnityEngine; +using Winch.Util; + +namespace Winch.Data.Boat; + +internal class VanillaBoatPaintData : BoatPaintData +{ + private int index = -1; + public int Index + { + get => index; + set + { + index = value; + id = value.ToString(); + name = $"color-{value}"; + questGridConfig = $"Paint{value}"; + } + } +} diff --git a/Winch/Data/BoatArea.cs b/Winch/Data/BoatArea.cs new file mode 100644 index 00000000..3ad54991 --- /dev/null +++ b/Winch/Data/BoatArea.cs @@ -0,0 +1,6 @@ +public enum BoatArea +{ + BASE = -1, + ROOF = 0, + HULL = 1, +} diff --git a/Winch/Data/ExtendedSaveData.cs b/Winch/Data/ExtendedSaveData.cs index a3663ff2..4f85396a 100644 --- a/Winch/Data/ExtendedSaveData.cs +++ b/Winch/Data/ExtendedSaveData.cs @@ -33,6 +33,9 @@ internal class ModdedSaveData public List mods = new List(); public string dockId = string.Empty; public int dockSlotIndex = 0; + public string boatRoofColor = string.Empty; + public string boatHullColor = string.Empty; + public string boatFlagStyle = string.Empty; public Dictionary grids = new Dictionary(); public List serializedCrabPotPOIs = new List(); public Dictionary> modData = new Dictionary>(); @@ -393,6 +396,34 @@ public bool IsSaveNotAllowedToBeLoaded() return false; } + public bool TryGetBoatRoofColor(out string boatRoofColor) + { + boatRoofColor = saveData.boatRoofColor; + return !string.IsNullOrWhiteSpace(boatRoofColor); + } + public void SetBoatRoofColor(string boatRoofColor) + { + saveData.boatRoofColor = boatRoofColor; + } + public bool TryGetBoatHullColor(out string boatHullColor) + { + boatHullColor = saveData.boatHullColor; + return !string.IsNullOrWhiteSpace(boatHullColor); + } + public void SetBoatHullColor(string boatHullColor) + { + saveData.boatHullColor = boatHullColor; + } + public bool TryGetBoatFlagStyle(out string boatFlagStyle) + { + boatFlagStyle = saveData.boatFlagStyle; + return !string.IsNullOrWhiteSpace(boatFlagStyle); + } + public void SetBoatFlagStyle(string boatFlagStyle) + { + saveData.boatFlagStyle = boatFlagStyle; + } + /// /// A participant of the saveData system. /// diff --git a/Winch/Patches/API/PlayerColorCustomizerPatcher.cs b/Winch/Patches/API/PlayerColorCustomizerPatcher.cs new file mode 100644 index 00000000..47de4f4d --- /dev/null +++ b/Winch/Patches/API/PlayerColorCustomizerPatcher.cs @@ -0,0 +1,74 @@ +using System; +using CommandTerminal; +using HarmonyLib; +using UnityEngine; +using Winch.Core; +using Winch.Data.Boat; +using Winch.Util; + +namespace Winch.Patches.API; + +[HarmonyPatch(typeof(PlayerColorCustomizer))] +internal static class PlayerColorCustomizerPatcher +{ + [HarmonyPrefix] + [HarmonyPriority(Priority.First)] + [HarmonyPatch(nameof(PlayerColorCustomizer.RefreshBoatColors))] + public static bool RefreshBoatColors_Prefix(PlayerColorCustomizer __instance) + { + var roofColor = SaveUtil.ActiveSaveData.TryGetBoatRoofColor(out string moddedRoofColor) && BoatUtil.TryGetBoatPaintData(moddedRoofColor, out BoatPaintData roofPaintData) ? roofPaintData.color : __instance.roofColors[GameManager.Instance.SaveData.RoofColorIndex]; + __instance.meshRenderers.ForEach(meshRenderer => + { + meshRenderer.materials[0].SetColor("_Roof_Color", roofColor); + }); + __instance.buntingMeshRenderers.ForEach(meshRenderer => + { + meshRenderer.materials[0].SetColor("_Roof_Color", roofColor); + }); + + + var hullColor = SaveUtil.ActiveSaveData.TryGetBoatHullColor(out string moddedHullColor) && BoatUtil.TryGetBoatPaintData(moddedHullColor, out BoatPaintData hullPaintData) ? hullPaintData.color : __instance.hullColors[GameManager.Instance.SaveData.HullColorIndex]; + __instance.meshRenderers.ForEach(meshRenderer => + { + meshRenderer.materials[0].SetColor("_Hull_Color", hullColor); + }); + __instance.buntingMeshRenderers.ForEach(meshRenderer => + { + meshRenderer.materials[0].SetColor("_Hull_Color", hullColor); + }); + return false; + } + + [HarmonyPrefix] + [HarmonyPriority(Priority.First)] + [HarmonyPatch(nameof(PlayerColorCustomizer.RefreshBoatFlag))] + public static bool RefreshBoatFlag_Prefix(PlayerColorCustomizer __instance) + { + if (SaveUtil.ActiveSaveData.TryGetBoatFlagStyle(out string moddedStyle) && BoatUtil.TryGetBoatFlagData(moddedStyle, out BoatFlagData boatFlagData)) + { + __instance.flagObjects.ForEach(WinchExtensions.Activate); + var flagMaterial = boatFlagData.FlagMaterial; + __instance.flagMeshRenderers.ForEach(flagMeshRenderer => flagMeshRenderer.material = flagMaterial); + return false; + } + return true; + } + + [HarmonyPrefix] + [HarmonyPriority(Priority.First)] + [HarmonyPatch(typeof(DredgeDialogueRunner), nameof(DredgeDialogueRunner.DebugChangeBoatColor))] + public static bool DebugChangeBoatColor_Prefix(CommandArg[] args) + { + BoatUtil.ChangeBoatColor((BoatArea)args[0].Int, args[1].String); + return false; + } + + [HarmonyPrefix] + [HarmonyPriority(Priority.First)] + [HarmonyPatch(typeof(DredgeDialogueRunner), nameof(DredgeDialogueRunner.DebugChangeBoatFlag))] + public static bool DebugChangeBoatFlag_Prefix(CommandArg[] args) + { + BoatUtil.ChangeBoatFlag(args[1].String); + return false; + } +} diff --git a/Winch/Serialization/Boat/BoatFlagDataConverter.cs b/Winch/Serialization/Boat/BoatFlagDataConverter.cs new file mode 100644 index 00000000..e9e0d79e --- /dev/null +++ b/Winch/Serialization/Boat/BoatFlagDataConverter.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using Winch.Data.Boat; +using Winch.Util; + +namespace Winch.Serialization.Boat; + +public class BoatFlagDataConverter : DredgeTypeConverter +{ + private readonly Dictionary _definitions = new() + { + { "id", new(string.Empty, null) }, + { "flagItem", new(string.Empty, null) }, + { "flagTexture", new(TextureUtil.GetTexture("FlagMaterialTemplate"), o=>TextureUtil.GetTexture(o.ToString())) }, + { "localizedNameKey", new(null, null) } + }; + + private readonly Dictionary _reroutes = new() + { + { "localizedNameKey", "id" } + }; + + public BoatFlagDataConverter() + { + AddDefinitions(_definitions); + AddReroutes(_reroutes); + } +} \ No newline at end of file diff --git a/Winch/Serialization/Boat/BoatPaintDataConverter.cs b/Winch/Serialization/Boat/BoatPaintDataConverter.cs new file mode 100644 index 00000000..21a6c20b --- /dev/null +++ b/Winch/Serialization/Boat/BoatPaintDataConverter.cs @@ -0,0 +1,27 @@ +using System.Collections.Generic; +using UnityEngine; +using Winch.Data.Boat; + +namespace Winch.Serialization.Boat; + +public class BoatPaintDataConverter : DredgeTypeConverter +{ + private readonly Dictionary _definitions = new() + { + { "id", new(string.Empty, null) }, + { "color", new(Color.white, o => DredgeTypeHelpers.GetColorFromJsonObject(o)) }, + { "localizedNameKey", new(null, null) }, + { "questGridConfig", new(null, null) } + }; + + private readonly Dictionary _reroutes = new() + { + { "localizedNameKey", "id" }, { "questGridConfig", "id" } + }; + + public BoatPaintDataConverter() + { + AddDefinitions(_definitions); + AddReroutes(_reroutes); + } +} \ No newline at end of file diff --git a/Winch/Util/BoatUtil.cs b/Winch/Util/BoatUtil.cs new file mode 100644 index 00000000..2ffcbc9b --- /dev/null +++ b/Winch/Util/BoatUtil.cs @@ -0,0 +1,501 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Google.Protobuf.WellKnownTypes; +using HarmonyLib; +using Sirenix.Utilities; +using UnityEngine; +using Winch.Core; +using Winch.Core.API; +using Winch.Data.Boat; +using Winch.Data.GridConfig; +using Winch.Serialization.Boat; +using Winch.Serialization.GridConfig; +using Yarn; + +namespace Winch.Util; + +public static class BoatUtil +{ + private static BoatFlagDataConverter BoatFlagDataConverter = new BoatFlagDataConverter(); + private static BoatPaintDataConverter BoatPaintDataConverter = new BoatPaintDataConverter(); + + internal static bool PopulateBoatFlagDataFromMetaWithConverter(BoatFlagData flagData, Dictionary meta) + { + return UtilHelpers.PopulateObjectFromMeta(flagData, meta, BoatFlagDataConverter); + } + + internal static bool PopulateBoatPaintDataFromMetaWithConverter(BoatPaintData paintData, Dictionary meta) + { + return UtilHelpers.PopulateObjectFromMeta(paintData, meta, BoatPaintDataConverter); + } + + internal static Dictionary VanillaBoatColorDict = new Dictionary + { + { 0, new Color(0.509804f, 0.3732026f, 0.3058824f, 1) }, + { 1, new Color(0.5836114f, 0.7009804f, 0.4198039f, 1) }, + { 2, new Color(0.3373774f, 0.3373774f, 0.4504902f, 1) }, + { 3, new Color(0.4941177f, 0.6588235f, 0.6039216f, 1) }, + { 4, new Color(0.8313726f, 0.4980392f, 0.3329412f, 1) }, + { 5, new Color(0.5019608f, 0.2906667f, 0.3963138f, 1) }, + { 6, new Color(0.8f, 0.6767473f, 0.32f, 1) }, + { 7, new Color(0.3009804f, 0.3009804f, 0.3009804f, 1) } + }; + internal static Dictionary VanillaBoatColorNameKeyDict = new Dictionary + { + { 0, "line:0466fdd" }, + { 1, "line:08ced27" }, + { 2, "line:0046243" }, + { 3, "line:0563aa7" }, + { 4, "line:056bb84" }, + { 5, "line:01d4a34" }, + { 6, "line:0824566" }, + { 7, "line:048fbac" } + }; + internal static Dictionary VanillaBoatFlagNameKeyDict = new Dictionary + { + { 0, "line:0530526" }, + { 1, "line:0dd4029" }, + { 2, "line:0f26fe9" }, + { 3, "line:08aed22" }, + { 4, "line:056bb84" }, + { 5, "line:01d4a34" }, + { 6, "line:0824566" }, + { 7, "line:048fbac" } + }; + internal static Dictionary VanillaBoatPaintDataDict = new Dictionary(); + internal static Dictionary VanillaBoatPaintDataIndexDict = new Dictionary(); + internal static Dictionary VanillaBoatFlagDataDict = new Dictionary(); + internal static Dictionary VanillaBoatFlagDataIndexDict = new Dictionary(); + internal static Dictionary ModdedBoatPaintDataDict = new Dictionary(); + internal static Dictionary ModdedBoatFlagDataDict = new Dictionary(); + internal static readonly int optionsPerPage = 4; + internal static List localizedNameKeys = new List(); + + public static BoatPaintData GetVanillaBoatPaintData(int index) + { + if (index <= 0) + return null; + + if (VanillaBoatPaintDataIndexDict.TryGetValue(index, out VanillaBoatPaintData boatPaintData)) + return boatPaintData; + else + return null; + } + + public static BoatPaintData GetModdedBoatPaintData(string id) + { + if (string.IsNullOrWhiteSpace(id)) + return null; + + if (ModdedBoatPaintDataDict.TryGetValue(id, out BoatPaintData boatPaintData)) + return boatPaintData; + else + return null; + } + + public static BoatPaintData GetBoatPaintData(string id) + { + if (string.IsNullOrWhiteSpace(id)) + return null; + + if (VanillaBoatPaintDataDict.TryGetValue(id, out BoatPaintData boatPaintData)) + return boatPaintData; + + if (ModdedBoatPaintDataDict.TryGetValue(id, out BoatPaintData moddedBoatPaintData)) + return moddedBoatPaintData; + + return null; + } + + public static bool TryGetBoatPaintData(string id, out BoatPaintData boatPaintData) + { + boatPaintData = null; + if (string.IsNullOrWhiteSpace(id)) + return false; + + if (VanillaBoatPaintDataDict.TryGetValue(id, out boatPaintData)) + return true; + + if (ModdedBoatPaintDataDict.TryGetValue(id, out boatPaintData)) + return true; + + return false; + } + + public static BoatFlagData GetVanillaBoatFlagData(int index) + { + if (index <= 0) + return null; + + if (VanillaBoatFlagDataIndexDict.TryGetValue(index, out VanillaBoatFlagData boatFlagData)) + return boatFlagData; + else + return null; + } + + public static BoatFlagData GetModdedBoatFlagData(string id) + { + if (string.IsNullOrWhiteSpace(id)) + return null; + + if (ModdedBoatFlagDataDict.TryGetValue(id, out BoatFlagData boatFlagData)) + return boatFlagData; + else + return null; + } + + public static BoatFlagData GetBoatFlagData(string id) + { + if (string.IsNullOrWhiteSpace(id)) + return null; + + if (VanillaBoatFlagDataDict.TryGetValue(id, out BoatFlagData boatFlagData)) + return boatFlagData; + + if (ModdedBoatFlagDataDict.TryGetValue(id, out BoatFlagData moddedBoatFlagData)) + return moddedBoatFlagData; + + return null; + } + + public static bool TryGetBoatFlagData(string id, out BoatFlagData boatFlagData) + { + boatFlagData = null; + if (string.IsNullOrWhiteSpace(id)) + return false; + + if (VanillaBoatFlagDataDict.TryGetValue(id, out boatFlagData)) + return true; + + if (ModdedBoatFlagDataDict.TryGetValue(id, out boatFlagData)) + return true; + + return false; + } + + internal static void Initialize() + { + foreach (var (index, color) in VanillaBoatColorDict) + { + var paintData = ScriptableObject.CreateInstance().DontDestroyOnLoad(); + paintData.Index = index; + paintData.color = color; + paintData.localizedNameKey = VanillaBoatColorNameKeyDict[index]; + localizedNameKeys.Add(paintData.localizedNameKey); + VanillaBoatPaintDataDict.Add(paintData.id, paintData); + VanillaBoatPaintDataIndexDict.Add(index, paintData); + } + foreach (var (index, localizedNameKey) in VanillaBoatFlagNameKeyDict) + { + var flagData = ScriptableObject.CreateInstance().DontDestroyOnLoad(); + flagData.Index = index; + flagData.localizedNameKey = localizedNameKey; + localizedNameKeys.Add(flagData.localizedNameKey); + VanillaBoatFlagDataDict.Add(flagData.id, flagData); + VanillaBoatFlagDataIndexDict.Add(index, flagData); + } + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", 49, Yarn.Instruction.Types.OpCode.AddOption, "line:01b7c6c", "JumpToModdedPaintPage", 0, false); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, "JumpToModdedPaintPage", Yarn.Instruction.Types.OpCode.PushFloat, 1); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.StoreVariable, "$modded_color_page_number"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.PushString, "Painter_Customize_Color_Page_Modded"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.StoreVariable, "$boat_customization_return_path"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.PushString, "Painter_Customize_Color_Pre"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.RunNode); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_2", -1, Yarn.Instruction.Types.OpCode.Stop); + + DialogueUtil.AddInstruction("Painter_Customize_Flag2", 23, Yarn.Instruction.Types.OpCode.AddOption, "line:0f9e0dd", "JumpToModdedFlagPage", 0, false); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, "JumpToModdedFlagPage", Yarn.Instruction.Types.OpCode.PushFloat, 1); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.StoreVariable, "$modded_flag_page_number"); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.PushString, "Painter_Customize_FlagModded"); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.RunNode); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Flag2", -1, Yarn.Instruction.Types.OpCode.Stop); + DredgeEvent.OnDialogueRunnerLoaded += OnDialogueRunnerLoaded; + } + + internal static void PostInitialize() + { + foreach (var (id, paintData) in ModdedBoatPaintDataDict) + { + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, id, Yarn.Instruction.Types.OpCode.PushString, id); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.StoreVariable, "$boat_customization_color_index"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.PushString, "Painter_Customize_Color_Selected"); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.RunNode); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_Color_Page_Modded", -1, Yarn.Instruction.Types.OpCode.Stop); + DialogueUtil.AddLineMetadata(paintData.localizedNameKey, "quest", "repeat"); + } + foreach (var (id, flagData) in ModdedBoatFlagDataDict) + { + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, id, Yarn.Instruction.Types.OpCode.PushString, id); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.StoreVariable, "$boat_flag_index"); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.PushString, "Painter_Customize_Flag_Selected"); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.RunNode); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.Pop); + DialogueUtil.AddInstruction("Painter_Customize_FlagModded", -1, Yarn.Instruction.Types.OpCode.Stop); + DialogueUtil.AddLineMetadata(flagData.localizedNameKey, "repeat"); + } + } + + private static void OnDialogueRunnerLoaded(DredgeDialogueRunner dialogueRunner) + { + dialogueRunner.AddFunction("GetModdedPaintPages", GetModdedPaintPages); + dialogueRunner.AddCommandHandler("AddModdedPaintPageOptions", AddModdedPaintPageOptions); + dialogueRunner.RemoveFunction("GetHasPaint"); + dialogueRunner.AddFunction("GetHasPaint", GetHasPaint); + dialogueRunner.AddCommandHandler("ShowPaintGrid", ShowPaintGrid); + dialogueRunner.RemoveCommandHandler("ChangeBoatColor"); + dialogueRunner.AddCommandHandler("ChangeBoatColor", (area, paintId) => ChangeBoatColor((BoatArea)area, paintId)); + + dialogueRunner.AddFunction("GetModdedFlagPages", GetModdedFlagPages); + dialogueRunner.AddCommandHandler("AddModdedFlagPageOptions", AddModdedFlagPageOptions); + dialogueRunner.RemoveFunction("GetIdOfFlagInInventoryAndStorage"); + dialogueRunner.AddFunction("GetIdOfFlagInInventoryAndStorage", GetIdOfFlagInInventoryAndStorage); + dialogueRunner.RemoveFunction("GetHasFlag"); + dialogueRunner.AddFunction("GetHasFlag", GetHasFlag); + dialogueRunner.AddCommandHandler("TakeFlag", TakeFlag); + dialogueRunner.RemoveCommandHandler("ChangeBoatFlag"); + dialogueRunner.AddCommandHandler("ChangeBoatFlag", ChangeBoatFlag); + } + + public static bool GetHasFlag(string flagId) => GameManager.Instance.SaveData.GetBoolVariable($"has-flag-{flagId}"); + public static void SetHasFlag(string flagId, bool hasFlag) => GameManager.Instance.SaveData.SetBoolVariable($"has-flag-{flagId}", hasFlag); + + internal static int GetModdedFlagPages() + { + var pages = Mathf.CeilToInt(ModdedBoatFlagDataDict.Count / (float)optionsPerPage); + WinchCore.Log.Error("GetModdedFlagPages " + pages); + return pages; + } + + internal static BoatFlagData[] GetFlagsForModdedPage(int moddedFlagPageNumber) + { + return ModdedBoatFlagDataDict.Values.Skip((moddedFlagPageNumber - 1) * optionsPerPage).Take(optionsPerPage).ToArray(); + } + + internal static void AddModdedFlagPageOptions(int moddedFlagPageNumber) + { + WinchCore.Log.Error("AddModdedFlagPageOptions " + moddedFlagPageNumber); + List> currentOptions = Traverse.Create(GameManager.Instance.DialogueRunner.Dialogue) + .Field("vm").Field("state").Field("currentOptions").GetValue>>(); + foreach (BoatFlagData flagData in GetFlagsForModdedPage(moddedFlagPageNumber)) + { + currentOptions.Add(new DialogueUtil.DredgeOption(flagData.localizedNameKey, flagData.id, GetHasFlag(flagData.id))); + } + } + + public static bool GetHasPaint(string paintId) => GameManager.Instance.SaveData.GetBoolVariable($"has-paint-{paintId}"); + public static void SetHasPaint(string paintId, bool hasPaint) => GameManager.Instance.SaveData.SetBoolVariable($"has-paint-{paintId}", hasPaint); + + private static Coroutine ShowPaintGrid(string paintId) + { + WinchCore.Log.Debug($"ShowPaintGrid({paintId})"); + if (TryGetBoatPaintData(paintId, out BoatPaintData boatPaintData)) + { + if (!string.IsNullOrWhiteSpace(boatPaintData.questGridConfig)) + { + var questGridConfig = boatPaintData.QuestGridConfig; + if (questGridConfig != null) + return GameManager.Instance.DialogueRunner.StartCoroutine(GameManager.Instance.DialogueRunner.ShowQuestGrid(boatPaintData.questGridConfig)); + else + WinchCore.Log.Error($"Failed to show paint grid for {paintId}. {boatPaintData.questGridConfig} is an invalid quest grid config ID!"); + } + else + WinchCore.Log.Error($"Failed to show paint grid for {paintId}. Missing the field \"questGridConfig\"!"); + } + else + WinchCore.Log.Error($"{paintId} is an invalid paint ID!"); + return null; + } + + internal static int GetModdedPaintPages() + { + var pages = Mathf.CeilToInt(ModdedBoatPaintDataDict.Count / (float)optionsPerPage); + WinchCore.Log.Error("GetModdedPaintPages " + pages); + return pages; + } + + internal static BoatPaintData[] GetPaintsForModdedPage(int moddedColorPageNumber) + { + return ModdedBoatPaintDataDict.Values.Skip((moddedColorPageNumber - 1) * optionsPerPage).Take(optionsPerPage).ToArray(); + } + + internal static void AddModdedPaintPageOptions(int moddedColorPageNumber) + { + WinchCore.Log.Error("AddModdedPaintPageOptions " + moddedColorPageNumber); + List> currentOptions = Traverse.Create(GameManager.Instance.DialogueRunner.Dialogue) + .Field("vm").Field("state").Field("currentOptions").GetValue>>(); + foreach (BoatPaintData paintData in GetPaintsForModdedPage(moddedColorPageNumber)) + { + currentOptions.Add(new DialogueUtil.DredgeOption(paintData.localizedNameKey, paintData.id, true)); + if (GetHasPaint(paintData.id)) + DialogueUtil.SetLineMetadata(paintData.localizedNameKey, "repeat", "paint"); + else + DialogueUtil.SetLineMetadata(paintData.localizedNameKey, "quest", "repeat"); + } + } + + public static string GetIdOfFlagInInventoryAndStorage() + { + var allItemsOfType = + GameManager.Instance.SaveData.Inventory.GetAllItemsOfType(ItemType.GENERAL, ItemSubtype.GENERAL) + .Concat(GameManager.Instance.SaveData.Storage.GetAllItemsOfType(ItemType.GENERAL, ItemSubtype.GENERAL)) + .ToItemData(); + var flag = allItemsOfType.FirstOrDefault(item => item is HarvestableItemData harvestableItem && harvestableItem.IsFlag()); + var id = flag != null ? flag.id : string.Empty; + WinchCore.Log.Debug($"GetIdOfFlagInInventoryAndStorage() returning {id}"); + return id; + } + + public static void TakeFlag(string flagId) + { + WinchCore.Log.Debug($"TakeFlag({flagId})"); + if (TryGetBoatFlagData(flagId, out BoatFlagData boatFlagData)) + { + GameManager.Instance.DialogueRunner.RemoveItemByIdInInventoryAndStorage(boatFlagData.flagItem); + GameManager.Instance.DialogueRunner.SetHasFlag(flagId, true); + } + else + WinchCore.Log.Error($"{flagId} is an invalid flag ID!"); + } + + public static void ChangeBoatFlag(string flagId) + { + WinchCore.Log.Debug($"ChangeBoatFlag({flagId})"); + if (TryGetBoatFlagData(flagId, out BoatFlagData boatFlagData)) + { + bool isVanilla = boatFlagData is VanillaBoatFlagData; + int flagIndex = boatFlagData is VanillaBoatFlagData vanilla ? vanilla.Index : -1; + GameManager.Instance.SaveData.BoatFlagStyle = flagIndex; + SaveUtil.ActiveSaveData.SetBoatFlagStyle(isVanilla ? string.Empty : flagId); + GameEvents.Instance.TriggerBoatFlagChanged(flagIndex); + DredgeEvent.TriggerBoatFlagChanged(flagId); + } + else + WinchCore.Log.Error($"{flagId} is an invalid flag ID!"); + } + + public static void ChangeBoatColor(BoatArea area, string paintId) + { + try + { + WinchCore.Log.Debug($"ChangeBoatColor({area},{paintId})"); + if (TryGetBoatPaintData(paintId, out BoatPaintData boatPaintData)) + { + bool isVanilla = boatPaintData is VanillaBoatPaintData; + int paintIndex = boatPaintData is VanillaBoatPaintData vanilla ? vanilla.Index : -1; + switch (area) + { + case BoatArea.ROOF: + GameManager.Instance.SaveData.RoofColorIndex = paintIndex; + SaveUtil.ActiveSaveData.SetBoatRoofColor(isVanilla ? string.Empty : paintId); + break; + case BoatArea.HULL: + GameManager.Instance.SaveData.HullColorIndex = paintIndex; + SaveUtil.ActiveSaveData.SetBoatHullColor(isVanilla ? string.Empty : paintId); + break; + default: + break; + } + GameManager.Instance.SaveData.HasChangedBoatColors = true; + GameEvents.Instance.TriggerBoatColorsChanged((int)area, paintIndex); + DredgeEvent.TriggerBoatColorsChanged(area, paintId); + } + else + WinchCore.Log.Error($"{paintId} is an invalid paint ID!"); + } + catch (Exception ex) + { + WinchCore.Log.Error(ex); + } + } + + internal static void AddBoatPaintDataFromMeta(string metaPath) + { + var meta = UtilHelpers.ParseMeta(metaPath); + if (meta == null) + { + WinchCore.Log.Error($"Meta file {metaPath} is empty"); + return; + } + var boatColorData = UtilHelpers.GetScriptableObjectFromMeta(meta, metaPath); + if (boatColorData == null) + { + WinchCore.Log.Error($"Couldn't create BoatPaintData"); + return; + } + var id = (string)meta["id"]; + if (VanillaBoatPaintDataDict.ContainsKey(id)) + { + WinchCore.Log.Error($"Boat paint {id} already exists in vanilla."); + return; + } + if (ModdedBoatPaintDataDict.ContainsKey(id)) + { + WinchCore.Log.Error($"Duplicate boat paint data {id} at {metaPath} failed to load"); + return; + } + if (PopulateBoatPaintDataFromMetaWithConverter(boatColorData, meta)) + { + if (localizedNameKeys.Contains(boatColorData.localizedNameKey)) + { + WinchCore.Log.Error($"Cannot reuse localized name keys! Failed to load for {id} at {metaPath}"); + return; + } + ModdedBoatPaintDataDict.Add(id, boatColorData); + localizedNameKeys.Add(boatColorData.localizedNameKey); + } + else + { + WinchCore.Log.Error($"No boat paint data converter found"); + } + } + + internal static void AddBoatFlagDataFromMeta(string metaPath) + { + var meta = UtilHelpers.ParseMeta(metaPath); + if (meta == null) + { + WinchCore.Log.Error($"Meta file {metaPath} is empty"); + return; + } + var boatFlagData = UtilHelpers.GetScriptableObjectFromMeta(meta, metaPath); + if (boatFlagData == null) + { + WinchCore.Log.Error($"Couldn't create BoatFlagData"); + return; + } + var id = (string)meta["id"]; + if (VanillaBoatFlagDataDict.ContainsKey(id)) + { + WinchCore.Log.Error($"Boat flag {id} already exists in vanilla."); + return; + } + if (ModdedBoatFlagDataDict.ContainsKey(id)) + { + WinchCore.Log.Error($"Duplicate boat flag data {id} at {metaPath} failed to load"); + return; + } + if (PopulateBoatFlagDataFromMetaWithConverter(boatFlagData, meta)) + { + if (localizedNameKeys.Contains(boatFlagData.localizedNameKey)) + { + WinchCore.Log.Error($"Cannot reuse localized name keys! Failed to load for {id} at {metaPath}"); + return; + } + ModdedBoatFlagDataDict.Add(id, boatFlagData); + localizedNameKeys.Add(boatFlagData.localizedNameKey); + } + else + { + WinchCore.Log.Error($"No boat flag data converter found"); + } + } +}