using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("com.binbin.OptimalPaths")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.1.2.0")]
[assembly: AssemblyInformationalVersion("1.1.2+393aa67bf4964ba09984857e60cd1bcb69b80b11")]
[assembly: AssemblyProduct("Optimal Paths")]
[assembly: AssemblyTitle("com.binbin.OptimalPaths")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.1.2.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace OptimalPaths
{
[HarmonyPatch]
public class OptimalPaths
{
private static string[] optimalPath = new string[2] { "sen_0", "sen_1" };
[HarmonyPrefix]
[HarmonyPatch(typeof(AtOManager), "AssignSingleGameNode")]
public static void AssignSingleGameNodePrefix(ref AtOManager __instance, ref Node _node)
{
Plugin.LogInfo("AssignSingleGameNode Prefix");
if (!Plugin.EnableOptimalPaths.Value || (Object)(object)_node == (Object)null || (Object)(object)_node.nodeData == (Object)null)
{
return;
}
if (Plugin.ForceAllNodes.Value || Plugin.ForceHighScoring.Value)
{
_node.nodeData.ExistsPercent = 100;
}
if (_node.nodeData.CombatPercent != 0 && Plugin.ForceHighScoring.Value)
{
_node.nodeData.CombatPercent = 100;
_node.nodeData.EventPercent = 0;
return;
}
if (_node.nodeData.CombatPercent != 0 && _node.nodeData.CombatPercent != 100 && Plugin.ForceRareEvents.Value)
{
_node.nodeData.CombatPercent = 0;
_node.nodeData.EventPercent = 100;
return;
}
int num = _node.nodeData.NodeEventPercent.Length;
if (num > 1 && (Plugin.ForceHighScoring.Value || Plugin.ForceRareEvents.Value))
{
Plugin.LogDebug(_node.nodeData.NodeId);
int[] array = new int[num];
array[num - 1] = 100;
_node.nodeData.NodeEventPercent = array;
}
}
[HarmonyPostfix]
[HarmonyPatch(typeof(Globals), "CreateGameContent")]
public static void CreateGameContentPostfix()
{
if (Plugin.EnableHighScoreLog.Value)
{
Plugin.LogInfo("Calculating optimal path");
Dictionary<string, Node> mapNodeDict = MapManager.Instance.GetMapNodeDict();
NodePathCode.PathScoreCalc();
}
}
[HarmonyPrefix]
[HarmonyPatch(typeof(Node), "AssignNode")]
public static void AssignNodePrefix(ref Node __instance)
{
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
//IL_00ac: Unknown result type (might be due to invalid IL or missing references)
//IL_00b1: Unknown result type (might be due to invalid IL or missing references)
Plugin.LogInfo("AssignNodePrefix - Setting Optimal Nodes to Red");
if (!Plugin.HighlightPath.Value || !optimalPath.Contains(__instance.nodeData.NodeId))
{
return;
}
ParticleSystem val = Traverse.Create((object)__instance).Field("nodeImageParticlesSystem").GetValue<ParticleSystem>();
if ((Object)(object)val == (Object)null)
{
Transform value = Traverse.Create((object)__instance).Field("nodeImageParticlesT").GetValue<Transform>();
if ((Object)(object)value == (Object)null)
{
Plugin.LogError("null nodeImageParticlesSystem");
return;
}
val = ((Component)value).GetComponent<ParticleSystem>();
}
MainModule main = val.main;
((MainModule)(ref main)).startColor = MinMaxGradient.op_Implicit(Color.red);
Traverse.Create((object)__instance).Field("nodeImageParticlesSystem").SetValue((object)val);
}
}
internal class NodePath
{
internal List<string> pathNodes = new List<string>();
internal int bossCount = 0;
internal int totalXP = 0;
internal int totalXP3 = 0;
internal int combatCount = 0;
internal int corruptorCount = 0;
}
public class NodePathCode
{
private static Dictionary<string, int> nodeExperience = new Dictionary<string, int>();
private static Dictionary<string, int> nodeExperience3Plus = new Dictionary<string, int>();
private static List<string> nodesWithCorruptor = new List<string>();
private static Dictionary<string, List<string>> nodeConnections = new Dictionary<string, List<string>>();
private static NodeData currentNode = null;
private static bool act3OrMore = false;
private static List<string> newZoneNodeIDs = new List<string> { "ulmin_0", "velka_0", "faen_0", "aqua_0", "wolf_0", "voidlow_0", "sen_0", "sahti_0", "dread_0" };
private static List<string> bossNodeIDs = new List<string>
{
"velka_12", "velka_9", "velka_27", "velka_32", "velka_25", "ulmin_56", "pyr_7", "ulmin_38", "secta_5", "sen_33",
"sen_27", "sen_31", "sewers_8", "faen_38", "faen_29", "faen_35", "faen_25", "spider_8", "aqua_27", "aqua_35",
"forge_6", "sahti_62", "sahti_36", "dread_11"
};
private static Dictionary<int, string> pathSteps = new Dictionary<int, string>();
private static Dictionary<string, List<NodePath>> nodePaths = new Dictionary<string, List<NodePath>>();
public static void PathScoreCalc()
{
Dictionary<string, NodeData> value = Traverse.Create((object)Globals.Instance).Field("_NodeDataSource").GetValue<Dictionary<string, NodeData>>();
act3OrMore = false;
foreach (NodeData value2 in value.Values)
{
nodeExperience[value2.NodeId] = GetNodeXP(value2);
}
act3OrMore = true;
foreach (NodeData value3 in value.Values)
{
nodeExperience3Plus[value3.NodeId] = GetNodeXP(value3);
}
foreach (string newZoneNodeID in newZoneNodeIDs)
{
AddPathStepNew(new List<string>(), newZoneNodeID);
}
foreach (string key in nodePaths.Keys)
{
foreach (NodePath item in nodePaths[key])
{
item.corruptorCount = 0;
foreach (string pathNode in item.pathNodes)
{
if (pathNode == "voidlow_26" || pathNode == "voidhigh_13")
{
item.bossCount += 2;
}
else if (bossNodeIDs.Contains(pathNode))
{
item.bossCount++;
}
if (nodeExperience.ContainsKey(pathNode))
{
item.totalXP += nodeExperience[pathNode];
}
if (nodeExperience3Plus.ContainsKey(pathNode))
{
item.totalXP3 += nodeExperience3Plus[pathNode];
}
if (nodesWithCorruptor.Contains(pathNode))
{
item.corruptorCount++;
}
}
Plugin.LogInfo("PATH\t" + string.Join(",", item.pathNodes) + "\t" + item.pathNodes.Count + "\t" + item.bossCount + "\t" + item.totalXP + "\t" + item.totalXP3 + "\t" + item.corruptorCount);
}
}
}
private static void AddPathStepNew(List<string> path, string curNodeID)
{
List<string> list = new List<string>(path);
list.Add(curNodeID);
if (!nodeConnections.ContainsKey(curNodeID))
{
NodePath nodePath = new NodePath();
nodePath.pathNodes = list;
if (!nodePaths.ContainsKey(list[0]))
{
nodePaths[list[0]] = new List<NodePath>();
}
nodePaths[list[0]].Add(nodePath);
return;
}
foreach (string item in nodeConnections[curNodeID])
{
if (!list.Contains(item) || item == "sen_12")
{
AddPathStepNew(list, item);
}
}
}
private static int GetNodeXP(NodeData _node)
{
if ((Object)(object)_node == (Object)null || (Object)(object)_node.NodeZone == (Object)null || _node.NodeZone.DisableExperienceOnThisZone || _node.NodeZone.ObeliskLow || _node.NodeZone.ObeliskHigh || _node.NodeZone.ObeliskFinal)
{
return 0;
}
Plugin.LogDebug("GetNodeXP: " + _node.NodeId);
currentNode = _node;
int num = 0;
EventData[] nodeEvent = _node.NodeEvent;
foreach (EventData @event in nodeEvent)
{
int eventXP = GetEventXP(@event, "event");
if (eventXP > num)
{
num = eventXP;
}
}
int num2 = 0;
CombatData[] nodeCombat = _node.NodeCombat;
foreach (CombatData combat in nodeCombat)
{
int combatXP = GetCombatXP(combat, "combat");
if (combatXP > num2)
{
num2 = combatXP;
}
}
NodeData[] nodesConnected = _node.NodesConnected;
foreach (NodeData val in nodesConnected)
{
ConnectPath(currentNode.NodeId, val.NodeId);
}
if (num2 == 0)
{
return num;
}
if (!_node.DisableCorruption && _node.NodeId != "sen_1" && _node.NodeId != "sen_2" && _node.NodeId != "sen_3" && _node.NodeId != "aqua_27")
{
nodesWithCorruptor.Add(_node.NodeId);
}
return num2;
}
private static int GetEventXP(EventData _event, string source)
{
if ((Object)(object)_event == (Object)null)
{
return 0;
}
int num = 0;
EventReplyData[] replys = _event.Replys;
foreach (EventReplyData reply in replys)
{
int replyXP = GetReplyXP(reply, source);
if (replyXP > num)
{
num = replyXP;
}
}
return num;
}
private static int GetReplyXP(EventReplyData _reply, string source)
{
if (_reply == null)
{
return 0;
}
int ssExperienceReward = _reply.SsExperienceReward;
ssExperienceReward += GetEventXP(_reply.SsEvent, source);
ssExperienceReward += GetCombatXP(_reply.SsCombat, source);
if ((Object)(object)_reply.SsNodeTravel != (Object)null)
{
ConnectPath(currentNode.NodeId, _reply.SsNodeTravel.NodeId);
}
if (_reply.SsRoll)
{
int flExperienceReward = _reply.FlExperienceReward;
flExperienceReward += GetEventXP(_reply.FlEvent, source);
flExperienceReward += GetCombatXP(_reply.FlCombat, source);
if (flExperienceReward > ssExperienceReward)
{
ssExperienceReward = flExperienceReward;
}
if ((Object)(object)_reply.FlNodeTravel != (Object)null)
{
ConnectPath(currentNode.NodeId, _reply.FlNodeTravel.NodeId);
}
if (_reply.SsRollNumberCritical != -1)
{
flExperienceReward = _reply.SscExperienceReward;
flExperienceReward += GetEventXP(_reply.SscEvent, source);
flExperienceReward += GetCombatXP(_reply.SscCombat, source);
if (flExperienceReward > ssExperienceReward)
{
ssExperienceReward = flExperienceReward;
}
if ((Object)(object)_reply.SscNodeTravel != (Object)null)
{
ConnectPath(currentNode.NodeId, _reply.SscNodeTravel.NodeId);
}
}
if (_reply.SsRollNumberCriticalFail != -1)
{
flExperienceReward = _reply.FlcExperienceReward;
flExperienceReward += GetEventXP(_reply.FlcEvent, source);
flExperienceReward += GetCombatXP(_reply.FlcCombat, source);
if (flExperienceReward > ssExperienceReward)
{
ssExperienceReward = flExperienceReward;
}
if ((Object)(object)_reply.FlcNodeTravel != (Object)null)
{
ConnectPath(currentNode.NodeId, _reply.FlcNodeTravel.NodeId);
}
}
}
return ssExperienceReward;
}
private static int GetCombatXP(CombatData _combat, string source)
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_005f: Unknown result type (might be due to invalid IL or missing references)
//IL_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Unknown result type (might be due to invalid IL or missing references)
//IL_0068: Unknown result type (might be due to invalid IL or missing references)
//IL_006a: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a3: Expected I4, but got Unknown
if ((Object)(object)_combat == (Object)null)
{
return 0;
}
int num = 0;
if ((int)currentNode.NodeCombatTier != 0 && !currentNode.DisableRandom && _combat.CombatId != "eaqua_37a" && _combat.CombatId != "eaqua_37b")
{
CombatTier nodeCombatTier = currentNode.NodeCombatTier;
CombatTier val = nodeCombatTier;
switch (val - 1)
{
case 0:
num += 21;
num += 59;
break;
case 1:
num += 35;
num += 94;
break;
case 2:
num += (act3OrMore ? 59 : 53);
num += (act3OrMore ? 185 : 162);
break;
case 3:
num += (act3OrMore ? 62 : 53);
num += (act3OrMore ? 193 : 174);
break;
case 4:
case 6:
num += (act3OrMore ? 65 : 61);
num += (act3OrMore ? 193 : 174);
break;
case 5:
num += (act3OrMore ? 62 : 53);
num += (act3OrMore ? 185 : 162);
break;
case 9:
num += 80;
num += 180;
break;
case 10:
case 11:
num += 80;
num += 240;
break;
default:
Plugin.LogError("Unsupported combat tier! node: " + currentNode.NodeId + " | combat: " + _combat.CombatId);
break;
}
}
else
{
NPCData[] nPCList = _combat.NPCList;
foreach (NPCData val2 in nPCList)
{
NPCData val3 = val2;
if (!((Object)(object)val3 == (Object)null))
{
if (act3OrMore && (Object)(object)val3.UpgradedMob != (Object)null)
{
val3 = val3.UpgradedMob;
}
if ((Object)(object)val3.NgPlusMob != (Object)null)
{
val3 = val3.NgPlusMob;
}
if ((Object)(object)val3.HellModeMob != (Object)null)
{
val3 = val3.HellModeMob;
}
num += val3.ExperienceReward;
}
}
}
return num + GetEventXP(_combat.EventData, source);
}
private static void ConnectPath(string nodeFrom, string nodeTo)
{
if (!newZoneNodeIDs.Contains(nodeTo))
{
if (!nodeConnections.ContainsKey(nodeFrom))
{
nodeConnections[nodeFrom] = new List<string>();
}
if (!nodeConnections[nodeFrom].Contains(nodeTo))
{
nodeConnections[nodeFrom].Add(nodeTo);
}
}
}
}
[BepInPlugin("com.binbin.OptimalPaths", "Optimal Paths", "1.1.2")]
[BepInProcess("AcrossTheObelisk.exe")]
public class Plugin : BaseUnityPlugin
{
internal int ModDate = int.Parse(DateTime.Today.ToString("yyyyMMdd"));
private readonly Harmony harmony = new Harmony("com.binbin.OptimalPaths");
internal static ManualLogSource Log;
public static string debugBase = "com.binbin.OptimalPaths ";
public static ConfigEntry<bool> EnableOptimalPaths { get; set; }
public static ConfigEntry<bool> HighlightPath { get; set; }
public static ConfigEntry<bool> ForceAllNodes { get; set; }
public static ConfigEntry<bool> ForceHighScoring { get; set; }
public static ConfigEntry<bool> ForceRareEvents { get; set; }
public static ConfigEntry<bool> EnableHighScoreLog { get; set; }
private void Awake()
{
//IL_002c: Unknown result type (might be due to invalid IL or missing references)
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_0047: Expected O, but got Unknown
//IL_0047: Expected O, but got Unknown
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
//IL_006e: Unknown result type (might be due to invalid IL or missing references)
//IL_0078: Expected O, but got Unknown
//IL_0078: Expected O, but got Unknown
//IL_008e: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Expected O, but got Unknown
//IL_00a9: Expected O, but got Unknown
//IL_00bf: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00da: Expected O, but got Unknown
//IL_00da: Expected O, but got Unknown
//IL_00f0: Unknown result type (might be due to invalid IL or missing references)
//IL_0101: Unknown result type (might be due to invalid IL or missing references)
//IL_010b: Expected O, but got Unknown
//IL_010b: Expected O, but got Unknown
//IL_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_0132: Unknown result type (might be due to invalid IL or missing references)
//IL_013c: Expected O, but got Unknown
//IL_013c: Expected O, but got Unknown
Log = ((BaseUnityPlugin)this).Logger;
Log.LogInfo((object)"com.binbin.OptimalPaths 1.1.2 has loaded!");
EnableOptimalPaths = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Enable Optimal Paths"), true, new ConfigDescription("If false, disables the mod. Restart the game upon changing this or any setting.", (AcceptableValueBase)null, Array.Empty<object>()));
ForceHighScoring = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Force Highscoring"), false, new ConfigDescription("If true, forces nodes to be in their highscoring variant. This overrides other settings. Restart the game after changing this.", (AcceptableValueBase)null, Array.Empty<object>()));
HighlightPath = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Highlight Path (WIP)"), false, new ConfigDescription("If true, highlights the optimal path in adventure mode with a red flare for each node. (Not implemented yet)", (AcceptableValueBase)null, Array.Empty<object>()));
ForceAllNodes = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Force All Nodes"), true, new ConfigDescription("If true, forces all nodes to spawn. Restart the game after changing this.", (AcceptableValueBase)null, Array.Empty<object>()));
ForceRareEvents = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Force Rare Events"), true, new ConfigDescription("If true, forces all nodes to have their rarest form. Also, nodes will prioritize events over combats. Restart the game after changing this.", (AcceptableValueBase)null, Array.Empty<object>()));
EnableHighScoreLog = ((BaseUnityPlugin)this).Config.Bind<bool>(new ConfigDefinition("Optimal Paths", "Enable High Score Log"), false, new ConfigDescription("If true, logs some additional high scoring info.", (AcceptableValueBase)null, Array.Empty<object>()));
harmony.PatchAll();
}
internal static void LogDebug(string msg)
{
Log.LogDebug((object)(debugBase + msg));
}
internal static void LogInfo(string msg)
{
Log.LogInfo((object)(debugBase + msg));
}
internal static void LogError(string msg)
{
Log.LogError((object)(debugBase + msg));
}
}
public static class PluginInfo
{
public const string PLUGIN_GUID = "com.binbin.OptimalPaths";
public const string PLUGIN_NAME = "Optimal Paths";
public const string PLUGIN_VERSION = "1.1.2";
}
}