Decompiled source of Reckss EliteAndScaling v1.3.7

plugins/Reckss-EliteAndScaling.dll

Decompiled a week ago
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;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ModHijack")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ModHijack")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("36654a57-7ef9-41f1-a6d1-6e7615d389e3")]
[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 Reckss.ErenshorMods;

[BepInPlugin("com.reckss.erenshor.eliteenemy", "Elite Enemy Mod", "1.3.7")]
public class EliteEnemyMod : BaseUnityPlugin
{
	public class EliteMarker : MonoBehaviour
	{
	}

	[HarmonyPatch(typeof(PlayerControl), "ConsiderOpponent")]
	public class ConsiderOpponentPatch
	{
		private static void Postfix(Character newTar, bool usedMouse)
		{
			if (!((Object)(object)newTar == (Object)null) && !((Object)(object)((Component)newTar).GetComponent<SimPlayer>() != (Object)null) && !((Object)newTar).name.Contains("Summoned"))
			{
				Stats myStats = newTar.MyStats;
				UpdateSocialLog.LogAdd($"<color=red>{((Object)newTar).name}: HP {myStats.CurrentHP}/{myStats.CurrentMaxHP}, Lvl {myStats.Level}</color>");
			}
		}
	}

	public ManualLogSource Logger;

	private ConfigEntry<float> spawnRangeCfg;

	private ConfigEntry<float> spawnIntervalCfg;

	private ConfigEntry<int> maxElitesCfg;

	private ConfigEntry<float> eliteScaleMultiplierCfg;

	private ConfigEntry<string> excludeFactionsCfg;

	private ConfigEntry<string> excludeScenesCfg;

	private ConfigEntry<string> excludeNamesCfg;

	private ConfigEntry<float> blessedDropChanceCfg;

	private ConfigEntry<int> lowLevelThresholdCfg;

	private ConfigEntry<int> midLevelThresholdCfg;

	private ConfigEntry<float> lowLevelMultCfg;

	private ConfigEntry<float> midLevelMultCfg;

	private ConfigEntry<float> highLevelMultCfg;

	private ConfigEntry<float> eliteHPMultiplierCfg;

	private ConfigEntry<float> eliteACMultiplierCfg;

	private ConfigEntry<float> eliteDamageMultiplierCfg;

	private ConfigEntry<float> eliteMoveSpeedMultiplierCfg;

	private ConfigEntry<float> dynamicMinMultCfg;

	private ConfigEntry<float> dynamicMaxMultCfg;

	private ConfigEntry<int> maxGameLevelCfg;

	private float lastSpawnTime;

	private readonly HashSet<Character> initialProcessed = new HashSet<Character>();

	private readonly HashSet<Character> processedElites = new HashSet<Character>();

	private readonly List<Character> currentElites = new List<Character>();

	private HashSet<Faction> excludeFactionSet;

	private HashSet<string> excludeSceneSet;

	private HashSet<string> manualExcludedNames;

	public static EliteEnemyMod Instance { get; private set; }

	private void Awake()
	{
		//IL_0019: Unknown result type (might be due to invalid IL or missing references)
		//IL_001f: Expected O, but got Unknown
		//IL_0347: Unknown result type (might be due to invalid IL or missing references)
		Instance = this;
		Logger = ((BaseUnityPlugin)this).Logger;
		Harmony val = new Harmony("com.reckss.erenshor.eliteenemy");
		val.PatchAll();
		spawnRangeCfg = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SpawnRange", 100f, "Max distance for elite logic.");
		spawnIntervalCfg = ((BaseUnityPlugin)this).Config.Bind<float>("General", "SpawnInterval", 15f, "Seconds between elite spawns.");
		maxElitesCfg = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxElites", 2, "Max simultaneous elites.");
		eliteScaleMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("General", "EliteScaleMultiplier", 2f, "Model scale multiplier.");
		excludeFactionsCfg = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludeFactions", "Player, Villager", "Factions to skip.");
		excludeScenesCfg = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludeScenes", "Main, LoadScene", "Scenes to skip.");
		excludeNamesCfg = ((BaseUnityPlugin)this).Config.Bind<string>("General", "ExcludeNames", "", "Enemy names to skip (comma-separated).");
		blessedDropChanceCfg = ((BaseUnityPlugin)this).Config.Bind<float>("General", "BlessedDropChance", 1f / 65f, "Chance for blessed drop.");
		lowLevelThresholdCfg = ((BaseUnityPlugin)this).Config.Bind<int>("LevelTiers", "LowLevelThreshold", 10, "Player level below which low-level multiplier applies.");
		midLevelThresholdCfg = ((BaseUnityPlugin)this).Config.Bind<int>("LevelTiers", "MidLevelThreshold", 50, "Player level below which mid-level multiplier applies.");
		lowLevelMultCfg = ((BaseUnityPlugin)this).Config.Bind<float>("LevelTiers", "LowLevelMult", 1.5f, "Multiplier for low-level players.");
		midLevelMultCfg = ((BaseUnityPlugin)this).Config.Bind<float>("LevelTiers", "MidLevelMult", 2f, "Multiplier for mid-level players.");
		highLevelMultCfg = ((BaseUnityPlugin)this).Config.Bind<float>("LevelTiers", "HighLevelMult", 2.5f, "Multiplier for high-level players.");
		eliteHPMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("EliteStats", "HP_Multiplier", 2.5f, "Base HP multiplier.");
		eliteACMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("EliteStats", "AC_Multiplier", 2.5f, "Base AC multiplier.");
		eliteDamageMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("EliteStats", "Damage_Multiplier", 2.5f, "Base damage multiplier.");
		eliteMoveSpeedMultiplierCfg = ((BaseUnityPlugin)this).Config.Bind<float>("EliteStats", "MoveSpeed_Multiplier", 1.2f, "Speed multiplier.");
		dynamicMinMultCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "DynamicMinMult", 1.5f, "Min extra multiplier.");
		dynamicMaxMultCfg = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "DynamicMaxMult", 3f, "Max extra multiplier.");
		maxGameLevelCfg = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "MaxGameLevel", 100, "Level at which scaling caps.");
		excludeFactionSet = new HashSet<Faction>();
		string[] array = excludeFactionsCfg.Value.Split(new char[1] { ',' });
		foreach (string text in array)
		{
			if (Enum.TryParse<Faction>(text.Trim(), ignoreCase: true, out Faction result))
			{
				excludeFactionSet.Add(result);
			}
		}
		excludeSceneSet = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		string[] array2 = excludeScenesCfg.Value.Split(new char[1] { ',' });
		foreach (string text2 in array2)
		{
			excludeSceneSet.Add(text2.Trim());
		}
		manualExcludedNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
		string[] array3 = excludeNamesCfg.Value.Split(new char[1] { ',' }, StringSplitOptions.RemoveEmptyEntries);
		foreach (string text3 in array3)
		{
			manualExcludedNames.Add(text3.Trim());
		}
		lastSpawnTime = 0f - spawnIntervalCfg.Value;
		Logger.LogInfo((object)"[EliteEnemyMod] v1.4.7 loaded");
	}

	private void Update()
	{
		//IL_0001: Unknown result type (might be due to invalid IL or missing references)
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		//IL_013c: Unknown result type (might be due to invalid IL or missing references)
		//IL_0141: Unknown result type (might be due to invalid IL or missing references)
		//IL_0074: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
		//IL_00b7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ed: Unknown result type (might be due to invalid IL or missing references)
		//IL_0237: Unknown result type (might be due to invalid IL or missing references)
		//IL_023c: Unknown result type (might be due to invalid IL or missing references)
		//IL_023e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0243: Unknown result type (might be due to invalid IL or missing references)
		//IL_0448: Unknown result type (might be due to invalid IL or missing references)
		//IL_04af: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b4: Unknown result type (might be due to invalid IL or missing references)
		//IL_04b6: Unknown result type (might be due to invalid IL or missing references)
		//IL_04bb: Unknown result type (might be due to invalid IL or missing references)
		Scene activeScene = SceneManager.GetActiveScene();
		string name = ((Scene)(ref activeScene)).name;
		if (excludeSceneSet.Contains(name))
		{
			return;
		}
		if (Input.GetKeyDown((KeyCode)292))
		{
			PlayerControl playerControl = GameData.PlayerControl;
			object obj;
			if (playerControl == null)
			{
				obj = null;
			}
			else
			{
				Character currentTarget = playerControl.CurrentTarget;
				obj = ((currentTarget != null) ? ((Component)currentTarget).GetComponent<Character>() : null);
			}
			Character val = (Character)obj;
			if ((Object)(object)val != (Object)null)
			{
				bool flag = excludeFactionSet.Add(val.MyFaction);
				excludeFactionsCfg.Value = string.Join(", ", excludeFactionSet);
				((BaseUnityPlugin)this).Config.Save();
				if (flag)
				{
					UpdateSocialLog.LogAdd($"<color=yellow>Excluding faction {val.MyFaction}</color>");
				}
				else
				{
					UpdateSocialLog.LogAdd($"<color=yellow>Faction {val.MyFaction} is already excluded</color>");
				}
			}
		}
		PlayerMeleeArea val2 = Object.FindObjectOfType<PlayerMeleeArea>();
		if ((Object)(object)val2 == (Object)null)
		{
			return;
		}
		Character componentInParent = ((Component)val2).GetComponentInParent<Character>();
		if ((Object)(object)componentInParent == (Object)null)
		{
			return;
		}
		Stats component = ((Component)componentInParent).GetComponent<Stats>();
		if ((Object)(object)component == (Object)null)
		{
			return;
		}
		Vector3 position = ((Component)val2).transform.position;
		float value = spawnRangeCfg.Value;
		float num = value * value;
		Character[] array = Object.FindObjectsOfType<Character>();
		Vector3 val4;
		foreach (Character val3 in array)
		{
			if (initialProcessed.Contains(val3) || processedElites.Contains(val3) || (Object)(object)val3 == (Object)(object)componentInParent || (Object)(object)((Component)val3).GetComponent<SimPlayer>() != (Object)null || ((Object)val3).name.Contains("Summoned") || manualExcludedNames.Contains(((Object)val3).name) || excludeFactionSet.Contains(val3.MyFaction))
			{
				continue;
			}
			Stats component2 = ((Component)val3).GetComponent<Stats>();
			if ((Object)(object)component2 == (Object)null || component2.CurrentHP <= 0)
			{
				continue;
			}
			val4 = ((Component)val3).transform.position - position;
			if (!(((Vector3)(ref val4)).sqrMagnitude > num))
			{
				if (component2.Level < component.Level)
				{
					int num2 = Mathf.RoundToInt((float)component.Level * 0.1f);
					component2.Level = Mathf.Clamp(component.Level + Random.Range(-num2, num2 + 1), 1, int.MaxValue);
					component2.CalcStats();
				}
				else
				{
					component2.CurrentMaxHP = Mathf.RoundToInt((float)component2.CurrentMaxHP * 1.5f);
					component2.CurrentHP = component2.CurrentMaxHP;
					component2.CurrentAC = Mathf.RoundToInt((float)component2.CurrentAC * 1.5f);
				}
				initialProcessed.Add(val3);
			}
		}
		if (!(Time.time - lastSpawnTime >= spawnIntervalCfg.Value))
		{
			return;
		}
		currentElites.RemoveAll(delegate(Character e)
		{
			int result;
			if (!((Object)(object)e == (Object)null))
			{
				Stats component4 = ((Component)e).GetComponent<Stats>();
				result = ((component4 != null && component4.CurrentHP <= 0) ? 1 : 0);
			}
			else
			{
				result = 1;
			}
			return (byte)result != 0;
		});
		if (currentElites.Count >= maxElitesCfg.Value)
		{
			return;
		}
		List<Character> list = new List<Character>(Object.FindObjectsOfType<Character>());
		for (int num3 = list.Count - 1; num3 >= 0; num3--)
		{
			Character val5 = list[num3];
			if (processedElites.Contains(val5) || currentElites.Contains(val5) || (Object)(object)val5 == (Object)(object)componentInParent)
			{
				list.RemoveAt(num3);
			}
			else if ((Object)(object)((Component)val5).GetComponent<SimPlayer>() != (Object)null || ((Object)val5).name.Contains("Summoned") || manualExcludedNames.Contains(((Object)val5).name))
			{
				list.RemoveAt(num3);
			}
			else if (excludeFactionSet.Contains(val5.MyFaction))
			{
				list.RemoveAt(num3);
			}
			else
			{
				Stats component3 = ((Component)val5).GetComponent<Stats>();
				if ((Object)(object)component3 == (Object)null || component3.CurrentHP <= 0 || component3.CurrentHP < component3.CurrentMaxHP)
				{
					list.RemoveAt(num3);
				}
				else
				{
					val4 = ((Component)val5).transform.position - position;
					if (((Vector3)(ref val4)).sqrMagnitude > num)
					{
						list.RemoveAt(num3);
					}
				}
			}
		}
		if (list.Count > 0)
		{
			Character val6 = list[Random.Range(0, list.Count)];
			PromoteToElite(val6, component);
			currentElites.Add(val6);
			UpdateSocialLog.LogAdd($"There are {currentElites.Count} Elites in the area.");
			lastSpawnTime = Time.time;
		}
	}

	public void PromoteToElite(Character enemy, Stats playerStats)
	{
		//IL_0031: Unknown result type (might be due to invalid IL or missing references)
		//IL_0225: Unknown result type (might be due to invalid IL or missing references)
		//IL_0235: Unknown result type (might be due to invalid IL or missing references)
		if ((Object)(object)enemy == (Object)null || (Object)(object)((Component)enemy).GetComponent<SimPlayer>() != (Object)null || ((Object)enemy).name.Contains("Summoned") || excludeFactionSet.Contains(enemy.MyFaction))
		{
			UpdateSocialLog.LogAdd("Cannot promote that target.", "red");
			return;
		}
		Stats component = ((Component)enemy).GetComponent<Stats>();
		if (!((Object)(object)component == (Object)null))
		{
			if (component.CurrentMaxHP < 15000)
			{
				component.CurrentMaxHP = 15000;
				component.CurrentHP = 15000;
			}
			int level = component.Level;
			component.Level = level + 15;
			component.CalcStats();
			float num = Mathf.Clamp01((float)playerStats.Level / (float)maxGameLevelCfg.Value);
			float num2 = Mathf.Lerp(dynamicMinMultCfg.Value, dynamicMaxMultCfg.Value, num);
			float num3 = ((playerStats.Level < lowLevelThresholdCfg.Value) ? lowLevelMultCfg.Value : ((playerStats.Level < midLevelThresholdCfg.Value) ? midLevelMultCfg.Value : highLevelMultCfg.Value));
			float num4 = num2 * num3;
			component.CurrentMaxHP = Mathf.RoundToInt((float)component.CurrentMaxHP * eliteHPMultiplierCfg.Value * num4);
			component.CurrentHP = component.CurrentMaxHP;
			component.CurrentAC = Mathf.RoundToInt((float)component.CurrentAC * eliteACMultiplierCfg.Value * num4);
			component.RunSpeed *= eliteMoveSpeedMultiplierCfg.Value * num4;
			NPC component2 = ((Component)enemy).GetComponent<NPC>();
			if ((Object)(object)component2 != (Object)null)
			{
				component2.BaseAtkDmg = Mathf.RoundToInt((float)component2.BaseAtkDmg * eliteDamageMultiplierCfg.Value * num4);
				component2.OHAtkDmg = Mathf.RoundToInt((float)component2.OHAtkDmg * eliteDamageMultiplierCfg.Value * num4);
			}
			((Object)enemy).name = ((Object)enemy).name + " Elite";
			Transform transform = ((Component)enemy).transform;
			transform.localScale *= eliteScaleMultiplierCfg.Value;
			((Component)enemy).gameObject.AddComponent<EliteMarker>();
			processedElites.Add(enemy);
		}
	}

	public void TryDropBlessed(Character enemy)
	{
		if ((Object)(object)enemy == (Object)null)
		{
			return;
		}
		LootTable component = ((Component)enemy).GetComponent<LootTable>();
		if (!((Object)(object)component == (Object)null) && component.ActualDropsQual != null && !(Random.value > blessedDropChanceCfg.Value))
		{
			for (int i = 0; i < component.ActualDropsQual.Count; i++)
			{
				component.ActualDropsQual[i] = 2;
			}
			Logger.LogInfo((object)("[EliteEnemyMod] Blessed for " + ((Object)enemy).name));
		}
	}
}
[HarmonyPatch(typeof(TypeText), "CheckCommands")]
public class PromoteCommandPatch
{
	private static bool Prefix(TypeText __instance)
	{
		Text typed = __instance.typed;
		if ((Object)(object)typed == (Object)null || !typed.text.Trim().Equals("/promote", StringComparison.OrdinalIgnoreCase))
		{
			return true;
		}
		Character val = GameData.PlayerControl?.CurrentTarget;
		if ((Object)(object)val == (Object)null)
		{
			UpdateSocialLog.LogAdd("No target.", "red");
			return false;
		}
		Character component = ((Component)val).GetComponent<Character>();
		if ((Object)(object)component == (Object)null || (Object)(object)((Component)component).GetComponent<SimPlayer>() != (Object)null || ((Object)component).name.Contains("Summoned"))
		{
			UpdateSocialLog.LogAdd("Cannot promote.", "red");
			return false;
		}
		PlayerMeleeArea val2 = Object.FindObjectOfType<PlayerMeleeArea>();
		object obj;
		if (val2 == null)
		{
			obj = null;
		}
		else
		{
			Character componentInParent = ((Component)val2).GetComponentInParent<Character>();
			obj = ((componentInParent != null) ? ((Component)componentInParent).GetComponent<Stats>() : null);
		}
		Stats val3 = (Stats)obj;
		if ((Object)(object)val3 == (Object)null)
		{
			UpdateSocialLog.LogAdd("Can't promote.", "red");
			return false;
		}
		EliteEnemyMod.Instance.PromoteToElite(component, val3);
		UpdateSocialLog.LogAdd("Promoted " + ((Object)component).name, "yellow");
		typed.text = string.Empty;
		__instance.CDFrames = 10f;
		__instance.InputBox.SetActive(false);
		GameData.PlayerTyping = false;
		return false;
	}
}