Decompiled source of LooneysBiggerMaps v1.4.0

LooneysBiggerMaps.dll

Decompiled 2 weeks ago
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
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("LooneysBiggerMaps")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("LooneysBiggerMaps")]
[assembly: AssemblyCopyright("Copyright ©  2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("7093db8f-4333-4a78-8fb7-7279a6a0f407")]
[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 Looney.LevelTuner;

[BepInPlugin("com.looney.leveltuner", "LooneysBiggerMaps", "1.4.0")]
public class LevelTunerPlugin : BaseUnityPlugin
{
	public const string PluginGuid = "com.looney.leveltuner";

	public const string PluginName = "LooneysBiggerMaps";

	public const string PluginVersion = "1.4.0";

	private Harmony _harmony;

	internal static ConfigEntry<bool> SimpleMode;

	internal static ConfigEntry<float> Simple_MapScale;

	internal static ConfigEntry<float> Simple_LootScale;

	internal static ConfigEntry<float> Simple_TrapScale;

	internal static ConfigEntry<float> Simple_EnemyScale;

	internal static ConfigEntry<string> ForcedSeed;

	internal static ConfigEntry<int> MapSizeBaseAdd;

	internal static ConfigEntry<float> MapSizeMultiplier;

	internal static ConfigEntry<int> MapSizeMinClamp;

	internal static ConfigEntry<int> HeatLevelAdd;

	internal static ConfigEntry<float> TrapMultiplier;

	internal static ConfigEntry<float> LootRichnessMultiplier;

	internal static ConfigEntry<int> ExtraFloorLoot;

	internal static ConfigEntry<int> ExtraItemPickups;

	internal static ConfigEntry<bool> PreferFloorWhenNoSpawnPoint;

	internal static ConfigEntry<float> EnemySpawnMultiplier;

	internal static ConfigEntry<float> EnemyWeightMultiplier;

	internal static ConfigEntry<bool> EnemyDeepScanRecursive;

	internal static ConfigEntry<bool> UpdateTickLogs;

	internal static ConfigEntry<float> UpdateTickInterval;

	internal static ManualLogSource LMain;

	internal static ManualLogSource LPreset;

	internal static ManualLogSource LGen;

	internal static ManualLogSource LRunner;

	internal static ManualLogSource LItems;

	internal static ManualLogSource LResources;

	internal static ManualLogSource LTraps;

	internal static ManualLogSource LEnemy;

	private float _tickNext;

	internal static bool UseSimple => SimpleMode.Value;

	internal static float Eff_MapSizeMult => UseSimple ? Mathf.Clamp(Simple_MapScale.Value, 0.5f, 10f) : Mathf.Max(0.1f, MapSizeMultiplier.Value);

	internal static int Eff_MapSizeMin => UseSimple ? 5 : Mathf.Max(1, MapSizeMinClamp.Value);

	internal static int Eff_MapSizeBaseAdd => (!UseSimple) ? MapSizeBaseAdd.Value : 0;

	internal static float Eff_LootRichness => UseSimple ? Mathf.Clamp(Simple_LootScale.Value, 0f, 10f) : Mathf.Max(0f, LootRichnessMultiplier.Value);

	internal static int Eff_ExtraFloorLoot => UseSimple ? Mathf.RoundToInt(10f * Mathf.Clamp(Simple_LootScale.Value, 0f, 10f)) : Mathf.Max(0, ExtraFloorLoot.Value);

	internal static int Eff_ExtraItemPickups => UseSimple ? Mathf.RoundToInt(5f * Mathf.Clamp(Simple_LootScale.Value, 0f, 10f)) : Mathf.Max(0, ExtraItemPickups.Value);

	internal static int Eff_HeatAdd => (!UseSimple) ? HeatLevelAdd.Value : 0;

	internal static float Eff_TrapMult => UseSimple ? Mathf.Clamp(Simple_TrapScale.Value, 0f, 10f) : Mathf.Max(0f, TrapMultiplier.Value);

	internal static float Eff_EnemySpawnMult => UseSimple ? Mathf.Clamp(Simple_EnemyScale.Value, 0f, 10f) : Mathf.Max(0f, EnemySpawnMultiplier.Value);

	internal static float Eff_EnemyWeightMult => UseSimple ? Mathf.Clamp(Simple_EnemyScale.Value, 0f, 10f) : Mathf.Max(0f, EnemyWeightMultiplier.Value);

	internal static bool Eff_EnemyDeepScan => EnemyDeepScanRecursive.Value;

	private static ConfigDescription Desc(string text, AcceptableValueBase range = null, int order = 0, string category = null, bool advanced = false)
	{
		//IL_000e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0014: Expected O, but got Unknown
		object[] array = TryMakeCMAttributes(order, category, advanced);
		return new ConfigDescription(text, range, array);
	}

	private static object[] TryMakeCMAttributes(int order, string category, bool advanced)
	{
		try
		{
			Type type = AccessTools.TypeByName("ConfigurationManager.ConfigurationManagerAttributes");
			if (type == null)
			{
				return null;
			}
			object obj = Activator.CreateInstance(type);
			type.GetField("Order")?.SetValue(obj, order);
			type.GetField("Category")?.SetValue(obj, category);
			type.GetField("IsAdvanced")?.SetValue(obj, advanced);
			return new object[1] { obj };
		}
		catch
		{
			return null;
		}
	}

	private void Awake()
	{
		//IL_0549: Unknown result type (might be due to invalid IL or missing references)
		//IL_0553: Expected O, but got Unknown
		LMain = Logger.CreateLogSource("LooneysBiggerMaps");
		LPreset = Logger.CreateLogSource("LooneysBiggerMaps (Patch_Generate)");
		LGen = Logger.CreateLogSource("LooneysBiggerMaps (GenRoutine)");
		LRunner = Logger.CreateLogSource("LooneysBiggerMaps (Runner)");
		LItems = Logger.CreateLogSource("LooneysBiggerMaps (Items)");
		LResources = Logger.CreateLogSource("LooneysBiggerMaps (Resources)");
		LTraps = Logger.CreateLogSource("LooneysBiggerMaps (Traps)");
		LEnemy = Logger.CreateLogSource("LooneysBiggerMaps (Enemy)");
		LMain.LogInfo((object)"Awake() called – setting up config and Harmony patches.");
		SimpleMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Simple Controls", "EnableSimpleMode", true, Desc("Use four easy sliders below; advanced settings are ignored while ON.", null, 100, "Simple Controls"));
		Simple_MapScale = ((BaseUnityPlugin)this).Config.Bind<float>("Simple Controls", "MapScale", 2f, Desc("How big are levels?\n1.0 = normal, 2.0 = ~2× bigger.\nRecommended: 1.0–5.0", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 10f), 90, "Simple Controls"));
		Simple_LootScale = ((BaseUnityPlugin)this).Config.Bind<float>("Simple Controls", "LootScale", 2f, Desc("How much loot?\n1.0 = normal, 2.0 = ~2× extra + richer stacks.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), 80, "Simple Controls"));
		Simple_TrapScale = ((BaseUnityPlugin)this).Config.Bind<float>("Simple Controls", "TrapScale", 2f, Desc("How many traps?\n1.0 = normal. Increases trap heat during spawn.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), 70, "Simple Controls"));
		Simple_EnemyScale = ((BaseUnityPlugin)this).Config.Bind<float>("Simple Controls", "EnemyScale", 2f, Desc("How many enemies?\nBoosts spawner caps/rates and enemy selection weights.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), 60, "Simple Controls"));
		ForcedSeed = ((BaseUnityPlugin)this).Config.Bind<string>("Advanced", "ForcedSeed", "", Desc("Optional: override the level seed. Leave empty to keep the game’s seed.", null, 1000, "Advanced", advanced: true));
		MapSizeBaseAdd = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "MapSizeBaseAdd", 0, Desc("(Advanced) Flat rooms added before multiplier.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-50, 200), 980, "Advanced", advanced: true));
		MapSizeMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "MapSizeMultiplier", 1f, Desc("(Advanced) Multiplies total rooms after base add.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 20f), 970, "Advanced", advanced: true));
		MapSizeMinClamp = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "MapSizeMinClamp", 5, Desc("(Advanced) Minimum final size after math.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(1, 200), 960, "Advanced", advanced: true));
		HeatLevelAdd = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "HeatLevelAdd", 0, Desc("(Advanced) Flat heat added before traps (affects spawn budgets).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(-50, 100), 940, "Advanced", advanced: true));
		TrapMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "TrapMultiplier", 1f, Desc("(Advanced) Temporary multiplier on heat DURING SpawnTraps.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), 930, "Advanced", advanced: true));
		LootRichnessMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "LootRichnessMultiplier", 1f, Desc("(Advanced) Multiplies resource stack sizes for EXTRA floor loot the mod spawns.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), 910, "Advanced", advanced: true));
		ExtraFloorLoot = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "ExtraFloorLoot", 20, Desc("(Advanced) Number of extra floor resource drops after generation.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), 900, "Advanced", advanced: true));
		ExtraItemPickups = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "ExtraItemPickups", 10, Desc("(Advanced) Number of extra fixed item pickups (uses remaining spawn points, then floor).", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 999), 890, "Advanced", advanced: true));
		PreferFloorWhenNoSpawnPoint = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "PreferFloorWhenNoSpawnPoint", true, Desc("(Advanced) If no spawn points remain, drop extra items on navigable floor.", null, 880, "Advanced", advanced: true));
		EnemySpawnMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "EnemySpawnMultiplier", 1f, Desc("(Advanced) Deep reflection multiplier for spawner caps/budgets/rates.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), 860, "Advanced", advanced: true));
		EnemyWeightMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Advanced", "EnemyWeightMultiplier", 1f, Desc("(Advanced) Multiplies enemy weights in LevelSegmentData arrays.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 20f), 850, "Advanced", advanced: true));
		EnemyDeepScanRecursive = ((BaseUnityPlugin)this).Config.Bind<bool>("Advanced", "EnemyDeepScanRecursive", true, Desc("(Advanced) Also scan nested structs/objects on EntitySpawner.", null, 840, "Advanced", advanced: true));
		UpdateTickLogs = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "UpdateTickLogs", false, Desc("Periodically log status while a level exists.", null, 100, "Debug", advanced: true));
		UpdateTickInterval = ((BaseUnityPlugin)this).Config.Bind<float>("Debug", "UpdateTickInterval", 2f, Desc("Seconds between tick logs (if enabled).", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.2f, 10f), 90, "Debug", advanced: true));
		LMain.LogInfo((object)"[LevelTuner] Build is CONFIG-ONLY (overlay compiled out). To enable UI, uncomment #define LOONEY_USE_IMGUI and add UnityEngine.IMGUIModule.dll.");
		_harmony = new Harmony("com.looney.leveltuner");
		_harmony.PatchAll();
		LMain.LogInfo((object)"LooneysBiggerMaps 1.4.0 loaded successfully.");
	}

	private void Update()
	{
		if (!UpdateTickLogs.Value)
		{
			return;
		}
		_tickNext -= Time.deltaTime;
		if (!(_tickNext <= 0f))
		{
			return;
		}
		_tickNext = Mathf.Max(0.2f, UpdateTickInterval.Value);
		try
		{
			LevelGenerator instance = LevelGenerator.instance;
			if ((Object)(object)instance != (Object)null)
			{
				LRunner.LogInfo((object)$"[Tick] finishedGenerating={instance.finishedGenerating}, rooms={instance.placedPieces?.Count ?? 0}, items={instance.itemPickups?.Count ?? 0}");
			}
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(LevelGenerator), "Generate")]
public static class Patch_Generate_RewritePreset
{
	private static void Prefix(ref LevelGeneratorPreset preset)
	{
		if (!string.IsNullOrEmpty(LevelTunerPlugin.ForcedSeed.Value))
		{
			preset.seed = LevelTunerPlugin.ForcedSeed.Value;
		}
		int size = preset.size;
		int size2 = preset.size;
		size2 += LevelTunerPlugin.Eff_MapSizeBaseAdd;
		size2 = Mathf.RoundToInt((float)size2 * LevelTunerPlugin.Eff_MapSizeMult);
		size2 = Mathf.Max(LevelTunerPlugin.Eff_MapSizeMin, size2);
		preset.size = size2;
		int heatLevel = preset.heatLevel;
		preset.heatLevel = Mathf.Max(0, preset.heatLevel + LevelTunerPlugin.Eff_HeatAdd);
		LevelTunerPlugin.LPreset.LogInfo((object)(LevelTunerPlugin.UseSimple ? $"[PresetRewrite] (Simple Mode) Map x{LevelTunerPlugin.Eff_MapSizeMult:0.##}, Loot x{LevelTunerPlugin.Eff_LootRichness:0.##}, Traps x{LevelTunerPlugin.Eff_TrapMult:0.##}, Enemies x{LevelTunerPlugin.Eff_EnemySpawnMult:0.##}" : $"[PresetRewrite] Size: {size}->{preset.size}, Heat: {heatLevel}->{preset.heatLevel}"));
		_ = LevelTunerRunner.Instance;
	}
}
[HarmonyPatch(typeof(LevelGenerator), "GenerationRoutine")]
public static class Patch_GenRoutine_HookEnd
{
	private static void Postfix(LevelGenerator __instance)
	{
		LevelTunerPlugin.LGen.LogInfo((object)"[GenRoutine] Hooked – scheduling post-generation extras.");
		LevelTunerRunner.Instance.RunAfterGeneration(__instance);
	}
}
[HarmonyPatch(typeof(LevelGenerator), "SpawnTraps")]
public static class Patch_SpawnTraps_HeatBoost
{
	private static int _savedHeat;

	private static void Prefix(LevelGenerator __instance)
	{
		if (__instance?.currentPreset != null)
		{
			_savedHeat = __instance.currentPreset.heatLevel;
			float eff_TrapMult = LevelTunerPlugin.Eff_TrapMult;
			if (eff_TrapMult > 0f && !Mathf.Approximately(eff_TrapMult, 1f))
			{
				int num = Mathf.RoundToInt((float)__instance.currentPreset.heatLevel * eff_TrapMult);
				__instance.currentPreset.heatLevel = Mathf.Max(0, num);
				LevelTunerPlugin.LTraps.LogInfo((object)$"[Traps] Heat boosted: {_savedHeat} -> {__instance.currentPreset.heatLevel} (x{eff_TrapMult})");
			}
		}
	}

	private static void Finalizer(LevelGenerator __instance)
	{
		if (__instance?.currentPreset != null)
		{
			__instance.currentPreset.heatLevel = _savedHeat;
		}
	}
}
[HarmonyPatch(typeof(LevelGenerator), "SpawnItems")]
public static class Patch_Log_SpawnItems
{
	private static int _before;

	private static void Prefix(LevelGenerator __instance)
	{
		_before = __instance.itemPickups?.Count ?? 0;
		LevelTunerPlugin.LItems.LogInfo((object)$"[SpawnItems] BEFORE: {_before}");
	}

	private static void Postfix(LevelGenerator __instance)
	{
		int num = __instance.itemPickups?.Count ?? 0;
		LevelTunerPlugin.LItems.LogInfo((object)$"[SpawnItems] AFTER: {num} (game +{Mathf.Max(0, num - _before)})");
	}
}
[HarmonyPatch(typeof(LevelGenerator), "SpawnResources")]
public static class Patch_Log_SpawnResources
{
	private static int _before;

	private static void Prefix(LevelGenerator __instance)
	{
		_before = __instance.itemPickups?.Count ?? 0;
		LevelTunerPlugin.LResources.LogInfo((object)$"[SpawnResources] BEFORE: {_before}");
	}

	private static void Postfix(LevelGenerator __instance)
	{
		int num = __instance.itemPickups?.Count ?? 0;
		LevelTunerPlugin.LResources.LogInfo((object)$"[SpawnResources] AFTER: {num} (resource ~+{Mathf.Max(0, num - _before)})");
	}
}
public class LevelTunerRunner : MonoBehaviour
{
	private static LevelTunerRunner _instance;

	public static LevelTunerRunner Instance
	{
		get
		{
			//IL_0016: Unknown result type (might be due to invalid IL or missing references)
			//IL_001c: Expected O, but got Unknown
			if ((Object)(object)_instance == (Object)null)
			{
				GameObject val = new GameObject("LooneyLevelTunerRunner");
				Object.DontDestroyOnLoad((Object)(object)val);
				_instance = val.AddComponent<LevelTunerRunner>();
				LevelTunerPlugin.LRunner.LogInfo((object)"[Runner] Created LooneyLevelTunerRunner.");
			}
			return _instance;
		}
	}

	public void RunAfterGeneration(LevelGenerator gen)
	{
		((MonoBehaviour)this).StartCoroutine(WaitAndDoPostGen(gen));
	}

	private IEnumerator WaitAndDoPostGen(LevelGenerator gen)
	{
		LevelTunerPlugin.LRunner.LogInfo((object)"[Runner] Waiting for finishedGenerating == true...");
		while ((Object)(object)gen != (Object)null && !gen.finishedGenerating)
		{
			yield return null;
		}
		if ((Object)(object)gen == (Object)null)
		{
			yield break;
		}
		LevelTunerPlugin.LRunner.LogInfo((object)"[Runner] Post-generation starting...");
		try
		{
			float wmul = LevelTunerPlugin.Eff_EnemyWeightMult;
			if (wmul > 0f && !Mathf.Approximately(wmul, 1f))
			{
				int changed = ScaleSegmentEnemyWeights(gen.currentSegmentData, wmul);
				LevelTunerPlugin.LEnemy.LogInfo((object)$"[EnemyWeights] Arrays changed: {changed} (x{wmul})");
			}
		}
		catch (Exception ex)
		{
			Exception e2 = ex;
			LevelTunerPlugin.LEnemy.LogWarning((object)$"[EnemyWeights] Failed: {e2}");
		}
		int extraPickupsPlaced = 0;
		try
		{
			extraPickupsPlaced = SpawnExtraItemPickups(gen, LevelTunerPlugin.Eff_ExtraItemPickups, LevelTunerPlugin.PreferFloorWhenNoSpawnPoint.Value);
		}
		catch (Exception e4)
		{
			LevelTunerPlugin.LRunner.LogWarning((object)$"[ExtraItemPickups] Failed: {e4}");
		}
		LevelTunerPlugin.LRunner.LogInfo((object)$"[Runner] ExtraItemPickups placed: {extraPickupsPlaced}");
		int extraFloorPlaced = 0;
		try
		{
			extraFloorPlaced = SpawnExtraFloorLoot(gen, LevelTunerPlugin.Eff_ExtraFloorLoot, LevelTunerPlugin.Eff_LootRichness);
		}
		catch (Exception e3)
		{
			LevelTunerPlugin.LRunner.LogWarning((object)$"[ExtraFloorLoot] Failed: {e3}");
		}
		LevelTunerPlugin.LRunner.LogInfo((object)$"[Runner] ExtraFloorLoot placed: {extraFloorPlaced}");
		int changedEnemy = 0;
		try
		{
			changedEnemy = EnemyDensityDeepReflect(LevelTunerPlugin.Eff_EnemySpawnMult, LevelTunerPlugin.Eff_EnemyDeepScan);
		}
		catch (Exception e)
		{
			LevelTunerPlugin.LEnemy.LogWarning((object)$"[EnemyTweak] Failed: {e}");
		}
		if (changedEnemy == 0)
		{
			LevelTunerPlugin.LEnemy.LogInfo((object)"[EnemyTweak] No matching fields changed (names may differ in this build).");
		}
		LevelTunerPlugin.LRunner.LogInfo((object)"[Runner] Post-generation complete.");
	}

	private int SpawnExtraItemPickups(LevelGenerator gen, int count, bool floorFallback)
	{
		//IL_00d1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d8: Expected O, but got Unknown
		//IL_00e1: Unknown result type (might be due to invalid IL or missing references)
		//IL_00eb: Expected O, but got Unknown
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_0135: Unknown result type (might be due to invalid IL or missing references)
		//IL_0173: Unknown result type (might be due to invalid IL or missing references)
		//IL_0178: Unknown result type (might be due to invalid IL or missing references)
		//IL_0182: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Unknown result type (might be due to invalid IL or missing references)
		//IL_018c: Unknown result type (might be due to invalid IL or missing references)
		//IL_018e: Unknown result type (might be due to invalid IL or missing references)
		//IL_0190: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ad: Unknown result type (might be due to invalid IL or missing references)
		if (count <= 0)
		{
			return 0;
		}
		List<ResourceSpawnPoint> list = ((Component)((Component)gen).transform).GetComponentsInChildren<ResourceSpawnPoint>(true).ToList();
		List<ItemPickup> list2 = new List<ItemPickup>();
		ItemPickup[] possibleItems = gen.possibleItems;
		foreach (ItemPickup val in possibleItems)
		{
			int num = Mathf.Max(1, val.facilitySpawnWeight);
			for (int j = 0; j < num; j++)
			{
				list2.Add(val);
			}
		}
		if (list2.Count == 0)
		{
			return 0;
		}
		int num2 = 0;
		Random random = gen.hostOnlyRand ?? new Random(1234);
		while (num2 < count)
		{
			ItemPickup val2 = list2[Random.Range(0, list2.Count)];
			InventoryItem val3 = new InventoryItem(val2.data);
			val3.resourceValues = new ResourceDictionary(val2.resources);
			if (list.Count > 0)
			{
				int index = random.Next(0, list.Count);
				ResourceSpawnPoint val4 = list[index];
				gen.itemPickups.Add(GameController.instance.CreateItemPickup(val3, ((Component)val4).transform.position, true, (Vector3?)((Component)val4).transform.eulerAngles, true));
				list.RemoveAt(index);
				Object.Destroy((Object)(object)val4);
			}
			else
			{
				if (!floorFallback)
				{
					break;
				}
				LevelPiece acceptableSpawnRoom = gen.GetAcceptableSpawnRoom(true);
				Vector3 val5 = gen.RandomNavMeshPointInRoom(acceptableSpawnRoom) + Vector3.up * 2f;
				if (val5 != Vector3.zero)
				{
					gen.itemPickups.Add(GameController.instance.CreateItemPickup(val3, val5, true, (Vector3?)null, true));
				}
			}
			num2++;
			if (gen.itemPickups.Count > 600)
			{
				break;
			}
		}
		return num2;
	}

	private int SpawnExtraFloorLoot(LevelGenerator gen, int count, float richnessMul)
	{
		//IL_00d4: Unknown result type (might be due to invalid IL or missing references)
		//IL_00d9: Unknown result type (might be due to invalid IL or missing references)
		//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
		//IL_0111: Unknown result type (might be due to invalid IL or missing references)
		//IL_0113: Unknown result type (might be due to invalid IL or missing references)
		//IL_0172: Unknown result type (might be due to invalid IL or missing references)
		//IL_0179: Expected O, but got Unknown
		//IL_017d: Unknown result type (might be due to invalid IL or missing references)
		//IL_0187: Expected O, but got Unknown
		//IL_0193: Unknown result type (might be due to invalid IL or missing references)
		//IL_0198: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01a7: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ae: Unknown result type (might be due to invalid IL or missing references)
		//IL_01b0: Unknown result type (might be due to invalid IL or missing references)
		//IL_013a: 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_0145: Unknown result type (might be due to invalid IL or missing references)
		//IL_0149: Unknown result type (might be due to invalid IL or missing references)
		//IL_0128: Unknown result type (might be due to invalid IL or missing references)
		//IL_012a: Unknown result type (might be due to invalid IL or missing references)
		//IL_0200: Unknown result type (might be due to invalid IL or missing references)
		//IL_01c9: Unknown result type (might be due to invalid IL or missing references)
		//IL_01ce: Unknown result type (might be due to invalid IL or missing references)
		//IL_01d8: Unknown result type (might be due to invalid IL or missing references)
		//IL_01dd: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e2: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e4: Unknown result type (might be due to invalid IL or missing references)
		//IL_01e6: Unknown result type (might be due to invalid IL or missing references)
		if (count <= 0 || (Object)(object)gen.floorResourceGroup == (Object)null)
		{
			return 0;
		}
		ItemPickup[] array = (from go in gen.floorResourceGroup.possibleResources
			select Object.op_Implicit((Object)(object)go) ? go.GetComponent<ItemPickup>() : null into ip
			where (Object)(object)ip != (Object)null
			select ip).ToArray();
		if (array.Length == 0)
		{
			return 0;
		}
		int num = 0;
		Random random = gen.hostOnlyRand ?? new Random(1234);
		while (num < count)
		{
			ItemPickup val = array[random.Next(0, array.Length)];
			Dictionary<ResourceTypes, int> dictionary = new Dictionary<ResourceTypes, int>();
			ResourceGroup[] resources = val.resources;
			foreach (ResourceGroup val2 in resources)
			{
				int num2 = Random.Range(val2.minValue, val2.maxValue + 1);
				int num3 = Mathf.Max(0, Mathf.RoundToInt((float)num2 * Mathf.Max(0f, richnessMul)));
				if (!dictionary.ContainsKey(val2.type))
				{
					dictionary.Add(val2.type, 0);
				}
				dictionary[val2.type] += num3;
			}
			InventoryItem val3 = new InventoryItem(val.data);
			val3.resourceValues = new ResourceDictionary(dictionary);
			LevelPiece acceptableSpawnRoom = gen.GetAcceptableSpawnRoom(true);
			Vector3 val4 = gen.RandomNavMeshPointInRoom(acceptableSpawnRoom) + Vector3.up * 2f;
			if (val4 == Vector3.zero)
			{
				val4 = gen.RandomNavMeshPointInRoom(gen.GetAcceptableSpawnRoom(true)) + Vector3.up * 2f;
				if (val4 == Vector3.zero)
				{
					break;
				}
			}
			ItemPickup item = GameController.instance.CreateItemPickup(val3, val4, true, (Vector3?)null, true);
			gen.itemPickups.Add(item);
			gen.floorItemPickups.Add(item);
			num++;
			if (gen.itemPickups.Count > 700)
			{
				break;
			}
		}
		return num;
	}

	private int ScaleSegmentEnemyWeights(LevelSegmentData seg, float mul)
	{
		if ((Object)(object)seg == (Object)null || mul <= 0f || Mathf.Approximately(mul, 1f))
		{
			return 0;
		}
		Type typeFromHandle = typeof(WeightedEntitySpawn);
		int num = 0;
		FieldInfo[] fields = ((object)seg).GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
		FieldInfo[] array = fields;
		foreach (FieldInfo fieldInfo in array)
		{
			if (!fieldInfo.FieldType.IsArray)
			{
				continue;
			}
			Type elementType = fieldInfo.FieldType.GetElementType();
			if (elementType != typeFromHandle)
			{
				continue;
			}
			string text = fieldInfo.Name.ToLowerInvariant();
			if (text.Contains("trap") || (!text.Contains("enemy") && !text.Contains("facility") && !text.Contains("surface")) || !(fieldInfo.GetValue(seg) is Array array2))
			{
				continue;
			}
			FieldInfo field = typeFromHandle.GetField("weight", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
			if (field == null)
			{
				continue;
			}
			int num2 = 0;
			for (int j = 0; j < array2.Length; j++)
			{
				object value = array2.GetValue(j);
				if (value == null)
				{
					continue;
				}
				try
				{
					int num3 = (int)field.GetValue(value);
					int num4 = Mathf.Max(0, Mathf.RoundToInt((float)num3 * mul));
					if (num4 != num3)
					{
						field.SetValue(value, num4);
						num2++;
						LevelTunerPlugin.LEnemy.LogDebug((object)$"[EnemyWeights] {fieldInfo.Name}[{j}].weight: {num3} -> {num4}");
					}
				}
				catch
				{
				}
			}
			if (num2 > 0)
			{
				num++;
				LevelTunerPlugin.LEnemy.LogInfo((object)$"[EnemyWeights] {fieldInfo.Name}: entries changed={num2}");
			}
		}
		return num;
	}

	private int EnemyDensityDeepReflect(float mul, bool recursive)
	{
		if (mul <= 0f || Mathf.Approximately(mul, 1f))
		{
			return 0;
		}
		Type type = AccessTools.TypeByName("EntitySpawner");
		if (type == null)
		{
			LevelTunerPlugin.LEnemy.LogWarning((object)"[EnemyTweak] Type 'EntitySpawner' not found.");
			return 0;
		}
		object obj2 = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null) ?? type.GetField("instance", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic)?.GetValue(null);
		if (obj2 == null)
		{
			LevelTunerPlugin.LEnemy.LogWarning((object)"[EnemyTweak] EntitySpawner.instance not found.");
			return 0;
		}
		int changed = 0;
		HashSet<object> visited = new HashSet<object>(ReferenceEqualityComparer.Instance);
		ScaleObject(obj2, "EntitySpawner", 0);
		LevelTunerPlugin.LEnemy.LogInfo((object)$"[EnemyTweak] Fields/props adjusted: {changed}");
		return changed;
		static bool IsUnityLike(Type t)
		{
			return typeof(Object).IsAssignableFrom(t) || typeof(Component).IsAssignableFrom(t) || typeof(GameObject).IsAssignableFrom(t) || t == typeof(Transform) || t == typeof(MonoBehaviour);
		}
		static bool LooksLikeCapName(string n)
		{
			n = n.ToLowerInvariant();
			return n.Contains("max") || n.Contains("limit") || n.Contains("budget") || n.Contains("pool") || n.Contains("cap") || n.Contains("quota") || n.Contains("heat") || n.Contains("tries") || n.Contains("attempt") || n.Contains("spawnrate") || n.Contains("rate");
		}
		void ScaleObject(object obj, string path, int depth)
		{
			if (obj != null && !visited.Contains(obj))
			{
				visited.Add(obj);
				Type type2 = obj.GetType();
				if (!IsUnityLike(type2) && depth <= (recursive ? 2 : 0))
				{
					FieldInfo[] fields = type2.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (FieldInfo fieldInfo in fields)
					{
						try
						{
							Type fieldType = fieldInfo.FieldType;
							string name = fieldInfo.Name;
							if (fieldType == typeof(int) && LooksLikeCapName(name))
							{
								int num = (int)fieldInfo.GetValue(obj);
								int num2 = Mathf.RoundToInt((float)num * mul);
								if (num2 != num && num2 >= 0)
								{
									fieldInfo.SetValue(obj, num2);
									changed++;
									LevelTunerPlugin.LEnemy.LogDebug((object)$"[EnemyTweak] {path}.{name}: {num} -> {num2}");
								}
							}
							else if (fieldType == typeof(float) && LooksLikeCapName(name))
							{
								float num3 = (float)fieldInfo.GetValue(obj);
								float num4 = num3 * mul;
								if (!Mathf.Approximately(num4, num3) && num4 >= 0f)
								{
									fieldInfo.SetValue(obj, num4);
									changed++;
									LevelTunerPlugin.LEnemy.LogDebug((object)$"[EnemyTweak] {path}.{name}: {num3} -> {num4}");
								}
							}
							else if (recursive)
							{
								if (fieldType.IsClass && !IsUnityLike(fieldType))
								{
									object value = fieldInfo.GetValue(obj);
									if (value != null)
									{
										ScaleObject(value, path + "." + name, depth + 1);
									}
								}
								else if (fieldType.IsValueType && !fieldType.IsPrimitive && !fieldType.IsEnum)
								{
									object value2 = fieldInfo.GetValue(obj);
									if (value2 != null)
									{
										ScaleObject(value2, path + "." + name, depth + 1);
										try
										{
											fieldInfo.SetValue(obj, value2);
										}
										catch
										{
										}
									}
								}
								else if (fieldType.IsArray && !IsUnityLike(fieldType.GetElementType()) && fieldInfo.GetValue(obj) is Array array)
								{
									for (int j = 0; j < array.Length; j++)
									{
										object value3 = array.GetValue(j);
										if (value3 != null)
										{
											ScaleObject(value3, $"{path}.{name}[{j}]", depth + 1);
										}
									}
								}
							}
						}
						catch
						{
						}
					}
					PropertyInfo[] properties = type2.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
					foreach (PropertyInfo propertyInfo in properties)
					{
						if (propertyInfo.CanRead && propertyInfo.CanWrite)
						{
							try
							{
								Type propertyType = propertyInfo.PropertyType;
								string name2 = propertyInfo.Name;
								if (propertyType == typeof(int) && LooksLikeCapName(name2))
								{
									int num5 = (int)propertyInfo.GetValue(obj);
									int num6 = Mathf.RoundToInt((float)num5 * mul);
									if (num6 != num5 && num6 >= 0)
									{
										propertyInfo.SetValue(obj, num6);
										changed++;
										LevelTunerPlugin.LEnemy.LogDebug((object)$"[EnemyTweak] {path}.{name2}: {num5} -> {num6}");
									}
								}
								else if (propertyType == typeof(float) && LooksLikeCapName(name2))
								{
									float num7 = (float)propertyInfo.GetValue(obj);
									float num8 = num7 * mul;
									if (!Mathf.Approximately(num8, num7) && num8 >= 0f)
									{
										propertyInfo.SetValue(obj, num8);
										changed++;
										LevelTunerPlugin.LEnemy.LogDebug((object)$"[EnemyTweak] {path}.{name2}: {num7} -> {num8}");
									}
								}
								else if (recursive && propertyType.IsClass && !IsUnityLike(propertyType))
								{
									object value4 = propertyInfo.GetValue(obj);
									if (value4 != null)
									{
										ScaleObject(value4, path + "." + name2, depth + 1);
									}
								}
							}
							catch
							{
							}
						}
					}
				}
			}
		}
	}
}
internal sealed class ReferenceEqualityComparer : IEqualityComparer<object>
{
	public static readonly ReferenceEqualityComparer Instance = new ReferenceEqualityComparer();

	public new bool Equals(object x, object y)
	{
		return x == y;
	}

	public int GetHashCode(object obj)
	{
		return RuntimeHelpers.GetHashCode(obj);
	}
}