using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using Bifrost.Cooked;
using HarmonyLib;
using LootExpansion;
using LootExpansion.Config;
using LootExpansion.Managers;
using LootExpansion.Services;
using MelonLoader;
using MelonLoader.Preferences;
using Microsoft.CodeAnalysis;
using MimicAPI.GameAPI;
using ReluProtocol;
using ReluProtocol.Enum;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: MelonInfo(typeof(Core), "LootExpansion", "1.0.1", "GOXH", null)]
[assembly: MelonGame("ReLUGames", "MIMESIS")]
[assembly: MelonOptionalDependencies(new string[] { "MimicAPI" })]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("LootExpansion")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: AssemblyInformationalVersion("1.0.2+716f6842d1cf35eb5493fb4776ee486e7e18d59d")]
[assembly: AssemblyProduct("LootExpansion")]
[assembly: AssemblyTitle("LootExpansion")]
[assembly: NeutralResourcesLanguage("en-US")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.2.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
namespace LootExpansion.Patches
{
[HarmonyPatch(typeof(DungeonRoom), "Initialize")]
internal static class DungeonRoomInitializePatch
{
private static void Postfix(DungeonRoom __instance)
{
LootExpansionManager.ConfigureForDungeon(__instance);
}
}
[HarmonyPatch(typeof(IVroom), "OnVacateRoom", new Type[] { typeof(bool) })]
internal static class DungeonRoomVacatePatch
{
private static void Postfix(IVroom __instance)
{
if (__instance is DungeonRoom)
{
LootExpansionManager.Reset();
}
}
}
[HarmonyPatch(typeof(VMonster), "OnDead")]
internal static class VMonsterOnDeadPatch
{
[HarmonyPostfix]
internal static void Postfix(VMonster __instance)
{
if (__instance != null)
{
LootExpansionManager.TryHandleMonsterDeath(__instance);
}
}
}
}
namespace LootExpansion.Services
{
internal static class LootSpawnService
{
internal static bool TrySpawnLoot(VMonster monster, int itemMasterId)
{
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0036: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Unknown result type (might be due to invalid IL or missing references)
//IL_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00af: Unknown result type (might be due to invalid IL or missing references)
try
{
if (monster == null || ((VActor)monster).VRoom == null)
{
return false;
}
ItemElement newItemElement = ((VActor)monster).VRoom.GetNewItemElement(itemMasterId, false, 1, 0, 0, 0);
if (newItemElement == null)
{
return false;
}
Vector3 positionVector = ((VActor)monster).PositionVector;
float num = 1.2f;
float num2 = Random.Range(0f, MathF.PI * 2f);
float num3 = Random.Range(0.2f, num);
float num4 = (float)Math.Cos(num2) * num3;
float num5 = (float)Math.Sin(num2) * num3;
PosWithRot val = ((VActor)monster).Position.Clone();
if (val != null)
{
val.x = positionVector.x + num4;
val.y = positionVector.y + 0.5f;
val.z = positionVector.z + num5;
val.yaw = Random.Range(0f, 360f);
}
return ((VActor)monster).VRoom.SpawnLootingObject(newItemElement, val, ((VActor)monster).IsIndoor, (ReasonOfSpawn)0, 0, 0, 0L, false) != 0;
}
catch (Exception ex)
{
MelonLogger.Error("[ ! ] LootExpansion - Spawn Service Error: " + ex.Message);
return false;
}
}
}
}
namespace LootExpansion.Managers
{
internal static class LootExpansionManager
{
private static readonly List<int> FallbackItemIds;
private static readonly List<int> ExcludedItemIds;
private static readonly List<int> ExcludedMonsterIds;
private static int _lastRoomHash;
private static float _lastLoadTime;
private static int _lastDeathObjId;
private static readonly HashSet<int> _processedMonsterHashes;
private static readonly HashSet<int> _loggedObjectIds;
private static readonly Dictionary<int, int> _itemPriceCache;
private static bool _isCollecting;
internal static void Reset()
{
FallbackItemIds.Clear();
_itemPriceCache.Clear();
_loggedObjectIds.Clear();
_processedMonsterHashes.Clear();
_lastDeathObjId = -1;
_isCollecting = false;
}
internal static void ConfigureForDungeon(DungeonRoom room)
{
if (room != null)
{
int hashCode = ((object)room).GetHashCode();
if (_lastRoomHash != hashCode || !(Time.time - _lastLoadTime < 0.1f))
{
_lastRoomHash = hashCode;
_lastLoadTime = Time.time;
Reset();
_isCollecting = true;
MelonLogger.Msg("[ ! ] Area change detected: Starting new item collection.");
MelonCoroutines.Start(DelayedSummaryLog(5f));
}
}
}
internal static void TryHandleMonsterDeath(VMonster monster)
{
if (monster == null || !LootExpansionM.Enabled)
{
return;
}
int objectID = ((VActor)monster).ObjectID;
int hashCode = ((object)monster).GetHashCode();
if (_lastDeathObjId == objectID || _processedMonsterHashes.Contains(hashCode))
{
return;
}
int num = ReflectionHelper.GetFieldValue<MonsterInfo>((object)monster, "_monsterInfo")?.MasterID ?? 0;
if (ExcludedMonsterIds.Contains(num))
{
return;
}
_lastDeathObjId = objectID;
_processedMonsterHashes.Add(hashCode);
switch (num)
{
case 20000011:
LootSpawnService.TrySpawnLoot(monster, 1000);
LootSpawnService.TrySpawnLoot(monster, 3000);
return;
case 20000009:
LootSpawnService.TrySpawnLoot(monster, 5139);
LootSpawnService.TrySpawnLoot(monster, 5163);
return;
}
float dropChance = LootExpansionM.DropChance;
int dropCountForMonster = LootExpansionM.GetDropCountForMonster(num);
int num2 = Mathf.Clamp(Mathf.RoundToInt(dropChance * 100f), 0, 100);
if (Random.Range(1, 101) > num2)
{
return;
}
for (int i = 0; i < dropCountForMonster; i++)
{
if (TryPickItem(out var itemMasterId, num))
{
LootSpawnService.TrySpawnLoot(monster, itemMasterId);
}
}
}
static LootExpansionManager()
{
FallbackItemIds = new List<int>();
_itemPriceCache = new Dictionary<int, int>();
_processedMonsterHashes = new HashSet<int>();
_loggedObjectIds = new HashSet<int>();
_lastRoomHash = -1;
_lastLoadTime = -1f;
_lastDeathObjId = -1;
ExcludedItemIds = new List<int> { 5124, 5110 };
ExcludedMonsterIds = new List<int> { 20000010, 20000001 };
}
internal static void LogLootingObjectSpawn(VLootingObject lootingObj)
{
if (lootingObj == null || !_loggedObjectIds.Add(((VActor)lootingObj).ObjectID))
{
return;
}
ItemElement itemElement = lootingObj.GetItemElement();
if (itemElement != null)
{
int itemMasterID = itemElement.ItemMasterID;
int price = itemElement.Price;
bool flag = ((VActor)lootingObj).VRoom is VWaitingRoom;
bool isIndoor = ((VActor)lootingObj).IsIndoor;
if (_isCollecting && !flag && isIndoor && !ExcludedItemIds.Contains(itemMasterID) && !FallbackItemIds.Contains(itemMasterID))
{
FallbackItemIds.Add(itemMasterID);
_itemPriceCache[itemMasterID] = price;
}
}
}
private static string GetLocalizedText(string key)
{
if (string.IsNullOrEmpty(key))
{
return "Unknown";
}
if (!key.StartsWith("STRING_"))
{
return key;
}
try
{
DataManager val = Object.FindAnyObjectByType<DataManager>();
ExcelDataManager val2 = (((Object)(object)val != (Object)null) ? val.ExcelDataManager : null);
if (((val2 != null) ? val2.LocalizationDict : null) != null && val2.LocalizationDict.TryGetValue(key, out var value))
{
return value.ko;
}
}
catch
{
}
return key;
}
internal static void ClearProcessedMonsters()
{
_processedMonsterHashes.Clear();
}
private static IEnumerator DelayedSummaryLog(float delay)
{
yield return (object)new WaitForSeconds(delay);
_isCollecting = false;
if (FallbackItemIds.Count > 0)
{
MelonLogger.Msg($"[ ! ] Loot pool confirmed for current area ({FallbackItemIds.Count} types)");
}
else
{
MelonLogger.Warning("[ ! ] No indoor items collected within 5 seconds of landing.");
}
}
private static bool TryPickItem(out int itemMasterId, int monsterId)
{
itemMasterId = 0;
if (FallbackItemIds.Count == 0)
{
return false;
}
double y = monsterId switch
{
20000004 => 3.5,
20000005 => 1.0,
20000006 => 0.9,
20000007 => 0.5,
20000008 => 2.0,
20000012 => 4.0,
_ => 1.0,
};
double num = 0.0;
List<double> list = new List<double>();
foreach (int fallbackItemId in FallbackItemIds)
{
if (_itemPriceCache.TryGetValue(fallbackItemId, out var value))
{
double num2 = Math.Pow(Math.Max(1, value), y);
list.Add(num2);
num += num2;
}
else
{
list.Add(0.0);
}
}
if (num <= 0.0)
{
return false;
}
double num3 = (double)Random.value * num;
double num4 = 0.0;
for (int i = 0; i < list.Count; i++)
{
num4 += list[i];
if (num3 <= num4)
{
itemMasterId = FallbackItemIds[i];
break;
}
}
return itemMasterId != 0;
}
}
}
namespace LootExpansion.Config
{
public static class LootExpansionM
{
private static MelonPreferences_Category _category;
private static MelonPreferences_Entry<bool> _enabled;
private static MelonPreferences_Entry<float> _dropChance;
private static MelonPreferences_Entry<int> _countSentryper;
private static MelonPreferences_Entry<int> _countStandingOwl;
private static MelonPreferences_Entry<int> _countBruteBunny;
private static MelonPreferences_Entry<int> _countQuakka;
private static MelonPreferences_Entry<int> _countMaegoostro;
private static MelonPreferences_Entry<int> _countMrDelpit;
public static bool Enabled
{
get
{
if (_enabled != null)
{
return _enabled.Value;
}
return false;
}
}
public static float DropChance
{
get
{
if (_dropChance == null)
{
return 0.1f;
}
return Mathf.Clamp01(_dropChance.Value);
}
}
public static void Initialize()
{
if (_category == null)
{
_category = MelonPreferences.CreateCategory("LootExpansion", "2077 Loot Expansion Settings");
_enabled = CreateEntry("Enabled", def: true, "Toggle Mod Activation (True/False)");
_dropChance = CreateEntry("Drop_Probability", 1f, "Drop Probability (0.1=10% / 1.0=100%)");
string display = "Number of items dropped on kill (Min:0 / Max:10)";
_countSentryper = CreateEntry("Sentryper_Count", 5, display);
_countBruteBunny = CreateEntry("BruteBunny_Count", 5, display);
_countMaegoostro = CreateEntry("Maegoostro_Count", 3, display);
_countStandingOwl = CreateEntry("StandingOwl_Count", 1, display);
_countMrDelpit = CreateEntry("MrDelpit_Count", 1, display);
_countQuakka = CreateEntry("Quakka_Count", 1, display);
_category.SaveToFile(false);
MelonLogger.Msg("[ ! ] Configuration has been successfully initialized.");
}
}
private static MelonPreferences_Entry<T> CreateEntry<T>(string id, T def, string display)
{
return _category.CreateEntry<T>(id, def, display, display, false, false, (ValueValidator)null, (string)null);
}
public static int GetDropCountForMonster(int monsterId)
{
int num = 0;
int num2 = 10;
return monsterId switch
{
20000004 => Mathf.Clamp(_countBruteBunny.Value, num, num2),
20000005 => Mathf.Clamp(_countMrDelpit.Value, num, num2),
20000006 => Mathf.Clamp(_countStandingOwl.Value, num, num2),
20000007 => Mathf.Clamp(_countQuakka.Value, num, num2),
20000008 => Mathf.Clamp(_countMaegoostro.Value, num, num2),
20000012 => Mathf.Clamp(_countSentryper.Value, num, num2),
_ => 0,
};
}
}
}
namespace LootExpansion.Patches
{
[HarmonyPatch(typeof(VMonster), "OnAlive")]
internal static class VMonsterOnAlivePatch
{
[HarmonyPostfix]
internal static void Postfix(VMonster __instance)
{
}
}
[HarmonyPatch(typeof(VLootingObject), "OnEnterSpace")]
internal static class VLootingObjectOnEnterSpacePatch
{
[HarmonyPostfix]
internal static void Postfix(VLootingObject __instance)
{
if (__instance != null)
{
LootExpansionManager.LogLootingObjectSpawn(__instance);
}
}
}
}
namespace LootExpansion
{
public sealed class Core : MelonMod
{
public override void OnInitializeMelon()
{
LootExpansionM.Initialize();
((MelonBase)this).HarmonyInstance.PatchAll();
MelonLogger.Msg("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
MelonLogger.Msg(">> [ 2077 // LOOT EXPANSION ] v1.0.1 INITIALIZED");
MelonLogger.Msg(">> AUTHORED BY : github.com/xxxx-6666");
MelonLogger.Msg(">> DISCORD SERVER : discord.com/cyber2077");
MelonLogger.Msg("---------------------------------------------------");
string arg = (LootExpansionM.Enabled ? "ONLINE" : "OFFLINE");
MelonLogger.Msg($" > SYSTEM_STATUS : {arg}");
MelonLogger.Msg($" > DROP_PROBABILITY : {LootExpansionM.DropChance:P0}");
MelonLogger.Msg(" > GLOBAL_LIMIT : 10 units (Safety Lock)");
MelonLogger.Msg("---------------------------------------------------");
MelonLogger.Msg(" > TARGET_DATABASE_INJECTION_REPORT:");
string[] array = new string[6] { "Sentryper ", "BruteBunny ", "Maegoostro ", "StandingOwl", "MrDelpit ", "Quakka " };
int[] array2 = new int[6] { 20000012, 20000004, 20000008, 20000006, 20000005, 20000007 };
for (int i = 0; i < array.Length; i++)
{
int dropCountForMonster = LootExpansionM.GetDropCountForMonster(array2[i]);
string arg2 = ((dropCountForMonster > 0) ? "[*]" : "[ ]");
MelonLogger.Msg($" {arg2} {array[i]} : {dropCountForMonster} qty");
}
MelonLogger.Msg("---------------------------------------------------");
MelonLogger.Msg(">> ACCESS GRANTED: SYSTEM_OVERRIDE_COMPLETE");
MelonLogger.Msg("+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+");
}
}
}