diff --git a/COTL_API/CustomWorldMapNode/CustomWorldMapNode.cs b/COTL_API/CustomWorldMapNode/CustomWorldMapNode.cs new file mode 100644 index 00000000..78c506d4 --- /dev/null +++ b/COTL_API/CustomWorldMapNode/CustomWorldMapNode.cs @@ -0,0 +1,20 @@ +using Lamb.UI; +using UnityEngine; + +namespace COTL_API.CustomWorldMapNode; +public abstract class CustomWorldMapNode +{ + internal string ModPrefix = ""; + internal WorldMapIcon.WorldMapRegion MapRegion { get; set; } + + public abstract string InternalName { get; } + public virtual FollowerLocation Location => FollowerLocation.None; + public virtual string? SceneToLoad => "Base Biome 1"; // unused if change OnLocationSelected + + public virtual string LayerLocation => "Base"; + public virtual Vector3 Position => new(0, 0, 0); + public virtual Vector2 ParallaxPosition => new(0, 0); + + public virtual Action? OnLocationSelected => null; // use default if null + public virtual Func? ShowConditions => null; // use default if null +} \ No newline at end of file diff --git a/COTL_API/CustomWorldMapNode/CustomWorldMapNodeManager.cs b/COTL_API/CustomWorldMapNode/CustomWorldMapNodeManager.cs new file mode 100644 index 00000000..df3e1303 --- /dev/null +++ b/COTL_API/CustomWorldMapNode/CustomWorldMapNodeManager.cs @@ -0,0 +1,23 @@ +using COTL_API.Guid; +using HarmonyLib; +using Lamb.UI; +using System.Reflection; + +namespace COTL_API.CustomWorldMapNode; +[HarmonyPatch] +public partial class CustomWorldMapNodeManager +{ + internal static Dictionary CustomWorldMapNodes { get; } = []; + public static WorldMapIcon.WorldMapRegion Add(CustomWorldMapNode node) + { + var guid = TypeManager.GetModIdFromCallstack(Assembly.GetCallingAssembly()); + + var mapRegion = GuidManager.GetEnumValue(guid, node.InternalName); + node.MapRegion = mapRegion; + node.ModPrefix = guid; + + CustomWorldMapNodes.Add(node.MapRegion, node); + + return mapRegion; + } +} \ No newline at end of file diff --git a/COTL_API/CustomWorldMapNode/CustomWorldMapNodePatches.cs b/COTL_API/CustomWorldMapNode/CustomWorldMapNodePatches.cs new file mode 100644 index 00000000..69a1dbb2 --- /dev/null +++ b/COTL_API/CustomWorldMapNode/CustomWorldMapNodePatches.cs @@ -0,0 +1,114 @@ +using HarmonyLib; +using Lamb.UI; +using UnityEngine; +using Object = UnityEngine.Object; + +namespace COTL_API.CustomWorldMapNode; +[HarmonyPatch] +public partial class CustomWorldMapNodeManager +{ + private static GameObject? NodeTemplate; + private static readonly Dictionary CustomWorldMapNodeList = []; + + [HarmonyPatch(typeof(UIWorldMapMenuController), nameof(UIWorldMapMenuController.Start))] + [HarmonyPostfix] + public static void UIWorldMapMenuController_Start(UIWorldMapMenuController __instance) + { + var mapContainerTransform = __instance._mapContainer.transform; + NodeTemplate = mapContainerTransform.Find("Locations/Base").gameObject; + } + + [HarmonyPatch(typeof(UIWorldMapMenuController), nameof(UIWorldMapMenuController.OnShowStarted))] + [HarmonyPrefix] + public static void UIWorldMapMenuController_OnShowStarted(UIWorldMapMenuController __instance) + { + CustomWorldMapNodeList.Clear(); + var mapContainerTransform = __instance._mapContainer.transform; + var locationsTransfrom = mapContainerTransform.Find("Locations"); + var layersTransform = mapContainerTransform.Find("Layers"); + if (layersTransform is null) + { + Log(BepInEx.Logging.LogLevel.Error, "Can't find Layers"); + return; + } + if (NodeTemplate is null) + { + Log(BepInEx.Logging.LogLevel.Error, "Can't find base node."); + return; + } + + var isOriginalObjectActive = NodeTemplate.activeSelf; + NodeTemplate.SetActive(false); + + foreach (var customWorldMapNode in CustomWorldMapNodes.Select(x => x.Value)) + { + var newWorldMapNode = Object.Instantiate(NodeTemplate, locationsTransfrom); + newWorldMapNode.name = customWorldMapNode.InternalName; + + var worldMapIcon = newWorldMapNode.GetComponent() ?? throw new Exception("WorldMapIcon not found!"); + worldMapIcon._location = customWorldMapNode.Location; + worldMapIcon._locationTerm = "NAMES/Places/" + customWorldMapNode.InternalName; + worldMapIcon._mapRegion = customWorldMapNode.MapRegion; + worldMapIcon._parallaxPosition = customWorldMapNode.ParallaxPosition; + var newScene = new InspectorScene + { + SceneName = customWorldMapNode.SceneToLoad, + }; + worldMapIcon._scene = newScene; + var layerToPutMarker = layersTransform.Find(customWorldMapNode.LayerLocation); + if (layerToPutMarker is null) + { + layerToPutMarker = layersTransform.Find("Base"); + Log(BepInEx.Logging.LogLevel.Warning, "Can't find layer to put marker, check the layer name"); + } + if (layerToPutMarker is null) throw new Exception("Something gone horribly wrong"); + worldMapIcon._layer = layerToPutMarker.GetComponent(); + var nodeMarker = new GameObject(customWorldMapNode.InternalName + "_Marker"); + var nodeMarkerTransform = nodeMarker.AddComponent(); + nodeMarker.transform.SetParent(layerToPutMarker); + nodeMarkerTransform.localPosition = customWorldMapNode.Position; + worldMapIcon._localPoint = nodeMarkerTransform; + if (customWorldMapNode.OnLocationSelected is null) + { + worldMapIcon.OnLocationSelected += new Action(__instance.OnLocationSelected); + } + else + { + worldMapIcon.OnLocationSelected = new Action(worldMapIcon => + { + if (__instance.isLoadingAssets) + { + return; + } + + if (worldMapIcon.Location != DataManager.Instance.CurrentLocation) + { + DataManager.Instance.CurrentLocation = worldMapIcon.Location; + __instance._canvasGroup.interactable = false; + __instance.Hide(true); + SaveAndLoad.Save(); + if (!DataManager.Instance.VisitedLocations.Contains(worldMapIcon.Location)) + { + DataManager.Instance.VisitedLocations.Add(worldMapIcon.Location); + } + } + }); + worldMapIcon.OnLocationSelected += customWorldMapNode.OnLocationSelected; + } + if (customWorldMapNode.ShowConditions is null) + { + if (DataManager.Instance.DiscoveredLocations.Contains(worldMapIcon.Location) || __instance._revealLocation == worldMapIcon.Location) + { + worldMapIcon.gameObject.SetActive(true); + } + } + else + { + if (customWorldMapNode.ShowConditions()) worldMapIcon.gameObject.SetActive(true); + } + CustomWorldMapNodeList.Add(customWorldMapNode.MapRegion, newWorldMapNode); + } + + NodeTemplate.SetActive(true); + } +} \ No newline at end of file diff --git a/COTL_API/Debug/DebugManager.cs b/COTL_API/Debug/DebugManager.cs index e2027406..b0af1e9a 100644 --- a/COTL_API/Debug/DebugManager.cs +++ b/COTL_API/Debug/DebugManager.cs @@ -8,6 +8,7 @@ using COTL_API.CustomStructures; using COTL_API.CustomTarotCard; using COTL_API.CustomTasks; +using COTL_API.CustomWorldMapNode; using FoodPlus.CustomTraits; using I2.Loc; using Lamb.UI; @@ -241,6 +242,8 @@ internal static void AddDebugContent() CustomTaskManager.Add(new DebugTask()); + CustomWorldMapNodeManager.Add(new DebugWorldMapNode()); + var test = CustomObjectiveManager.BedRest("Test"); test.InitialQuestText = "This is my custom quest text for this objective."; diff --git a/COTL_API/Debug/DebugWorldMapNode.cs b/COTL_API/Debug/DebugWorldMapNode.cs new file mode 100644 index 00000000..33344bd8 --- /dev/null +++ b/COTL_API/Debug/DebugWorldMapNode.cs @@ -0,0 +1,13 @@ +using UnityEngine; + +namespace COTL_API.Debug; +internal class DebugWorldMapNode : CustomWorldMapNode.CustomWorldMapNode +{ + public override string InternalName => "Graveyard_Test"; + public override FollowerLocation Location => FollowerLocation.Graveyard_Location; + public override string? SceneToLoad => "Graveyard"; + public override string LayerLocation => "Shore Front"; + public override Vector2 ParallaxPosition => new(58, 118); + public override Vector3 Position => new (826f, -840f, 0f); + public override Func? ShowConditions => () => true; +}