using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("PerkRespec")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("PerkRespec")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("5d88a250-062a-4cbf-bbcf-9f398539636d")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace PerkRespec
{
public class GameConfig
{
public const bool RespecNotAllowedOutsideByDefault = false;
public bool IsModEnabled => EnabledEntry?.Value ?? true;
public bool AllowRespecFromAnywhere => AllowRespecFromAnywhereEntry?.Value ?? false;
private ConfigEntry<bool> AllowRespecFromAnywhereEntry { get; set; } = null;
private ConfigEntry<bool> EnabledEntry { get; set; } = null;
public GameConfig(ConfigFile config)
{
EnabledEntry = config.Bind<bool>("General", "EnableMod", true, "Enable or disable the mod");
AllowRespecFromAnywhereEntry = config.Bind<bool>("General", "AllowRespecFromAnywhere", false, "true: allow the respec from anywhere; false: allow respec only in towns");
}
}
public static class GameProvider
{
public static ManualLogSource Log { get; set; }
public static GameConfig Config { get; set; }
public static BaseUnityPlugin Plugin { get; set; }
}
[BepInPlugin("scotilen.perkrespec", "PerkRespec", "1.0.1")]
public class GamePlugin : BaseUnityPlugin
{
private void Awake()
{
//IL_003b: Unknown result type (might be due to invalid IL or missing references)
GameProvider.Plugin = (BaseUnityPlugin)(object)this;
GameProvider.Config = new GameConfig(((BaseUnityPlugin)this).Config);
GameProvider.Log = ((BaseUnityPlugin)this).Logger;
((BaseUnityPlugin)this).Logger.LogInfo((object)"PerkRespec loaded");
new Harmony("scotilen.perkrespec").PatchAll();
}
}
public class Versioning
{
public const string ModIdentifier = "scotilen.perkrespec";
public const string ModName = "PerkRespec";
public const string WebsiteUrl = "https://github.com/miguelcjalmeida/PerkRespec";
public const string Description = "Allow respec of perks in any city, or in any moment if you prefer.";
public const string Author = "Scotilen";
public const string SemanticVersion = "1.0.1";
public const int LastUpdateDate = 20251221;
public static IList<string> Dependencies = DetermineDependencies();
private static IList<string> DetermineDependencies()
{
List<string> list = new List<string>();
list.Add("BepInEx-BepInExPack_AcrossTheObelisk-5.4.23");
return list;
}
}
}
namespace PerkRespec.AllowPerkRespecing
{
public class AllowPerkRespecUseCase
{
public int originalCityTier = 0;
public bool originalCharIsInTown = false;
public void PretendToBeInFirstCity(int originalCityTier, bool originalCharIsInTown)
{
if (GameProvider.Config.IsModEnabled && ShouldAllowPerkEditing())
{
this.originalCityTier = originalCityTier;
this.originalCharIsInTown = originalCharIsInTown;
GameProvider.Log.LogInfo((object)"Pretending to be in first city");
SetTownTier(0);
SetCharInTown(isInTown: true);
}
}
public void StopPretending()
{
if (GameProvider.Config.IsModEnabled)
{
GameProvider.Log.LogInfo((object)"Stopped pretending to be in first city");
SetTownTier(originalCityTier);
SetCharInTown(originalCharIsInTown);
}
}
private bool ShouldAllowPerkEditing()
{
if ((Object)(object)PerkTree.Instance == (Object)null)
{
return false;
}
if ((Object)(object)AtOManager.Instance == (Object)null)
{
return false;
}
if (GameProvider.Config.AllowRespecFromAnywhere)
{
return true;
}
return AtOManager.Instance.CharInTown();
}
private void SetTownTier(int tier)
{
GameProvider.Log.LogInfo((object)$"Setting town tier to {tier}");
SetAttributeValue(AtOManager.Instance, "townTier", tier);
AtOManager.Instance.gameHandicap = tier;
}
private void SetCharInTown(bool isInTown)
{
if (GameProvider.Config.AllowRespecFromAnywhere)
{
string text = (isInTown ? "yes" : "no");
GameProvider.Log.LogInfo((object)("Setting char to be in town? " + text));
SetAttributeValue(AtOManager.Instance, "charInTown", isInTown);
}
}
private void SetAttributeValue(object instance, string key, object value)
{
if (instance == null)
{
return;
}
Type type = instance.GetType();
if (!(type == null))
{
FieldInfo field = type.GetField(key, BindingFlags.Instance | BindingFlags.NonPublic);
if (!(field == null))
{
field.SetValue(instance, value);
}
}
}
}
public class PerkRespecPatches
{
[HarmonyPatch(typeof(PerkTree), "Show")]
public class PerkTreeShowPatch
{
public static AllowPerkRespecUseCase useCase = new AllowPerkRespecUseCase();
public static void Prefix()
{
int townTier = AtOManager.Instance.GetTownTier();
bool originalCharIsInTown = AtOManager.Instance.CharInTown();
useCase.PretendToBeInFirstCity(townTier, originalCharIsInTown);
}
}
[HarmonyPatch(typeof(PerkTree), "HideAction")]
public class PerkTreeHideActionPatch
{
public static void Postfix()
{
PerkTreeShowPatch.useCase.StopPretending();
}
}
}
}