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