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;
}
}