using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using KillCountEvolution.Config; using TMPro; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("KillCountEvolution")] [assembly: AssemblyDescription("")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("MobLevelSystem")] [assembly: AssemblyCopyright("Copyright © 2026")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("b0de67da-3bbf-4641-bf42-71bdb5d846ed")] [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")] [HarmonyPatch(typeof(EnemyHud), "UpdateHuds")] internal class EnemyHudPatch { private static void Postfix(EnemyHud __instance) { if (!(AccessTools.Field(typeof(EnemyHud), "m_huds").GetValue(__instance) is IDictionary dictionary)) { return; } foreach (DictionaryEntry item in dictionary) { object key = item.Key; Character val = (Character)((key is Character) ? key : null); if ((Object)(object)val == (Object)null) { continue; } int level = val.GetLevel(); if (level <= 3) { continue; } object value = item.Value; if (value == null) { continue; } FieldInfo fieldInfo = AccessTools.Field(value.GetType(), "m_name"); if (!(fieldInfo == null)) { object? value2 = fieldInfo.GetValue(value); TMP_Text val2 = (TMP_Text)((value2 is TMP_Text) ? value2 : null); if (!((Object)(object)val2 == (Object)null) && !val2.text.Contains("★")) { int count = level - 1; string text = new string('★', count); val2.text = val2.text + " " + text + ""; } } } } } namespace KillCountEvolution { [BepInPlugin("com.basicMods.KillCountEvolution", "Kill Count Evolution", "1.0.0")] public class KillCountEvolution : BaseUnityPlugin { public static KillCountEvolution Instance; public MobSpawnConfig mobConfig; public PlayerData localPlayerData; private string saveFolder; private Dictionary onlinePeerContributions = new Dictionary(); private int globalTotalKills; private void Awake() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) Instance = this; saveFolder = Path.Combine(Paths.BepInExRootPath, "plugins", "KillCountEvolution"); Directory.CreateDirectory(saveFolder); mobConfig = new MobSpawnConfig((BaseUnityPlugin)(object)this); new Harmony("com.basicMods.KillCountEvolution").PatchAll(); } public void SetupRPCs() { ZRoutedRpc.instance.Register("RPC_SubmitInitialKills", (Action)RPC_SubmitInitialKills); ZRoutedRpc.instance.Register("RPC_SyncGlobalKills", (Action)RPC_SyncGlobalKills); ZRoutedRpc.instance.Register("RPC_AddOneKill", (Action)RPC_AddOneKill); } private void RPC_SubmitInitialKills(long sender, int kills) { if (ZNet.instance.IsServer()) { onlinePeerContributions[sender] = kills; UpdateGlobalTotal(); } } private void RPC_AddOneKill(long sender) { if (ZNet.instance.IsServer()) { if (onlinePeerContributions.ContainsKey(sender)) { onlinePeerContributions[sender]++; } else { onlinePeerContributions[sender] = 1; } UpdateGlobalTotal(); } } private void RPC_SyncGlobalKills(long sender, int total) { globalTotalKills = total; } private void UpdateGlobalTotal() { globalTotalKills = onlinePeerContributions.Values.Sum(); ZRoutedRpc.instance.InvokeRoutedRPC(ZRoutedRpc.Everybody, "RPC_SyncGlobalKills", new object[1] { globalTotalKills }); SaveMasterJson(); } public void OnPlayerDisconnect(long peerID) { if (ZNet.instance.IsServer() && onlinePeerContributions.ContainsKey(peerID)) { onlinePeerContributions.Remove(peerID); UpdateGlobalTotal(); } } public void LoadLocalData() { if (!((Object)(object)Player.m_localPlayer == (Object)null)) { string worldName = ZNet.instance.GetWorldName(); string playerName = Player.m_localPlayer.GetPlayerName(); string path = Path.Combine(saveFolder, worldName + "_" + playerName + ".json"); if (File.Exists(path)) { string text = File.ReadAllText(path); localPlayerData = JsonUtility.FromJson(text); Debug.Log((object)$"[KillCountEvolution] Betöltve: {playerName} - {localPlayerData.TotalKills} ölés."); } else { localPlayerData = new PlayerData { PlayerName = playerName, TotalKills = 0 }; Debug.Log((object)"[KillCountEvolution] Új player adat létrehozva."); } ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RPC_SubmitInitialKills", new object[1] { localPlayerData.TotalKills }); } } public void RegisterLocalKill() { localPlayerData.TotalKills++; SaveLocalJson(); ZRoutedRpc.instance.InvokeRoutedRPC(0L, "RPC_AddOneKill", Array.Empty()); } private void SaveLocalJson() { string worldName = ZNet.instance.GetWorldName(); File.WriteAllText(Path.Combine(saveFolder, worldName + "_" + localPlayerData.PlayerName + ".json"), JsonUtility.ToJson((object)localPlayerData, true)); } public void SaveMasterJson(bool forceZero = false) { if (!((Object)(object)ZNet.instance == (Object)null)) { int num = ((!forceZero) ? globalTotalKills : 0); File.WriteAllText(Path.Combine(saveFolder, ZNet.instance.GetWorldName() + "_MASTER.json"), "{\"GlobalOnlineKills\": " + num + "}"); } } public int GetTotalKills() { return globalTotalKills; } public void ClearGlobalData() { onlinePeerContributions.Clear(); globalTotalKills = 0; } } [Serializable] public class PlayerData { public string PlayerName; public int TotalKills; } [HarmonyPatch(typeof(ZNet), "Awake")] internal class ZNet_Awake_Patch { private static void Postfix() { KillCountEvolution.Instance.SetupRPCs(); } } [HarmonyPatch(typeof(Player), "OnSpawned")] internal class Player_Spawn_Patch { private static void Postfix() { KillCountEvolution.Instance.LoadLocalData(); } } [HarmonyPatch(typeof(ZNet), "Shutdown")] internal class ZNet_Shutdown_Patch { private static void Prefix() { if ((Object)(object)KillCountEvolution.Instance != (Object)null && (Object)(object)ZNet.instance != (Object)null && ZNet.instance.IsServer()) { KillCountEvolution.Instance.ClearGlobalData(); KillCountEvolution.Instance.SaveMasterJson(forceZero: true); } } } [HarmonyPatch(typeof(Character), "Damage")] internal class Damage_Patch { private static void Postfix(Character __instance, HitData hit) { if ((Object)(object)__instance == (Object)null || hit == null || !(__instance.GetHealth() <= 0f) || __instance.IsPlayer()) { return; } Character attacker = hit.GetAttacker(); Player val = (Player)(object)((attacker is Player) ? attacker : null); if ((Object)(object)val != (Object)null && (Object)(object)val == (Object)(object)Player.m_localPlayer) { string prefabName = ((Object)__instance).name.Replace("(Clone)", "").Trim(); if (!KillCountEvolution.Instance.mobConfig.IsPrefabExcluded(prefabName)) { KillCountEvolution.Instance.RegisterLocalKill(); } } } } public static class RankManager { public static int RollCustomLevel(int originalLevel) { MobSpawnConfig mobConfig = KillCountEvolution.Instance.mobConfig; int totalKills = KillCountEvolution.Instance.GetTotalKills(); float num = mobConfig.Chance5Star.Value + Mathf.Min((float)totalKills * mobConfig.BonusPerKill5Star.Value, mobConfig.MaxBonus5Star.Value); float num2 = mobConfig.Chance4Star.Value + Mathf.Min((float)totalKills * mobConfig.BonusPerKill4Star.Value, mobConfig.MaxBonus4Star.Value); float num3 = mobConfig.Chance3Star.Value + Mathf.Min((float)totalKills * mobConfig.BonusPerKill3Star.Value, mobConfig.MaxBonus3Star.Value); float num4 = num + num2 + num3; float num5 = Mathf.Clamp(mobConfig.VanillaMinSpawnRate.Value, 0f, 100f); float num6 = 100f - num5; float num7; if (num5 <= 0f) { num7 = num4; } else { if (num4 > num6) { float num8 = num6 / num4; num *= num8; num2 *= num8; num3 *= num8; num4 = num6; } num7 = 100f; } if (num7 <= 0f) { return originalLevel; } float num9 = Random.Range(0f, num7); if (num9 < num) { return 6; } if (num9 < num + num2) { return 5; } if (num9 < num + num2 + num3) { return 4; } return originalLevel; } } [HarmonyPatch(typeof(Character), "SetLevel")] public static class SetLevelOverridePatch { private static void Prefix(Character __instance, ref int level) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null || __instance.IsPlayer()) { return; } ZNetView component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null || !component.IsOwner() || (Object)(object)KillCountEvolution.Instance == (Object)null || KillCountEvolution.Instance.mobConfig == null) { return; } string prefabName = ((Object)__instance).name.Replace("(Clone)", "").Trim(); if (KillCountEvolution.Instance.mobConfig.IsPrefabExcluded(prefabName)) { return; } Biome currentBiome = Heightmap.FindBiome(((Component)__instance).transform.position); if (!KillCountEvolution.Instance.mobConfig.IsBiomeExcluded(currentBiome) && (int)__instance.m_faction != 1 && level <= 3) { int num = level; int num2 = RankManager.RollCustomLevel(num); if (num2 > num) { level = num2; } } } } [HarmonyPatch(typeof(Character), "Awake")] internal class CharacterAwakePatch { private static void Postfix(Character __instance) { //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_0085: Invalid comparison between Unknown and I4 if ((Object)(object)__instance == (Object)null || __instance.IsPlayer() || (Object)(object)KillCountEvolution.Instance == (Object)null || KillCountEvolution.Instance.mobConfig == null) { return; } string prefabName = ((Object)__instance).name.Replace("(Clone)", "").Trim(); if (!KillCountEvolution.Instance.mobConfig.IsPrefabExcluded(prefabName)) { Biome currentBiome = Heightmap.FindBiome(((Component)__instance).transform.position); if (!KillCountEvolution.Instance.mobConfig.IsBiomeExcluded(currentBiome) && (int)__instance.m_faction != 1 && __instance.GetLevel() == 1) { __instance.SetLevel(1); } } } } } namespace KillCountEvolution.Config { public class MobSpawnConfig { public ConfigEntry Chance3Star; public ConfigEntry Chance4Star; public ConfigEntry Chance5Star; public ConfigEntry ExcludedBiomes; public ConfigEntry ExcludedPrefabsConfig; public ConfigEntry BonusPerKill3Star; public ConfigEntry BonusPerKill4Star; public ConfigEntry BonusPerKill5Star; public ConfigEntry MaxBonus3Star; public ConfigEntry MaxBonus4Star; public ConfigEntry MaxBonus5Star; public ConfigEntry VanillaMinSpawnRate; public ConfigEntry LootBonusBlacklist; private HashSet excludedPrefabsSet = new HashSet(); private HashSet lootBlacklistSet = new HashSet(); private static readonly string[] InternalBlacklist = new string[41] { "Eikthyr", "gd_king", "Bonemass", "Dragon", "GoblinKing", "SeekerQueen", "Fader", "Brenna", "Geirrhafa", "GoblinBrute_Hildir", "GoblinShaman_Hildir", "Skeleton_Hildir", "Fenring_Cultist_Hildir", "Goblin_Hildir", "Charred_Melee_Dyrnwyn", "Haldor", "Hildir", "BogWitch", "Hugin", "Munin", "Odin", "Dverger", "DvergerMage", "DvergerMageFire", "DvergerMageIce", "DvergerMageSupport", "DvergerAshlands", "Boar", "Wolf", "Lox", "Asksvin", "Hen", "Chicken", "Deer", "Hare", "Neck", "Seagal", "Crow", "AshCrow", "Leviathan", "Bat" }; public MobSpawnConfig(BaseUnityPlugin plugin) { Chance3Star = plugin.Config.Bind("Rates", "BaseChance3Star", 5f, "Base chance for 3-star (Level 4) spawn (%). Calculated 3-star bonus rates adds to this base."); Chance4Star = plugin.Config.Bind("Rates", "BaseChance4Star", 2f, "Base chance for 4-star (Level 5) spawn (%). Calculated 4-star bonus rates adds to this base."); Chance5Star = plugin.Config.Bind("Rates", "BaseChance5Star", 0.5f, "Base chance for 5-star (Level 6) spawn (%). Calculated 5-star bonus rates adds to this base."); BonusPerKill3Star = plugin.Config.Bind("Progression", "BonusPerKill3Star", 0.02f, "Bonus % added to 3-star chance per kill."); BonusPerKill4Star = plugin.Config.Bind("Progression", "BonusPerKill4Star", 0.01f, "Bonus % added to 4-star chance per kill."); BonusPerKill5Star = plugin.Config.Bind("Progression", "BonusPerKill5Star", 0.005f, "Bonus % added to 5-star chance per kill."); MaxBonus3Star = plugin.Config.Bind("Progression", "MaxBonus3Star", 20f, "Maximum total bonus % for 3-star chance."); MaxBonus4Star = plugin.Config.Bind("Progression", "MaxBonus4Star", 18f, "Maximum total bonus % for 4-star chance."); MaxBonus5Star = plugin.Config.Bind("Progression", "MaxBonus5Star", 9.5f, "Maximum total bonus % for 5-star chance."); VanillaMinSpawnRate = plugin.Config.Bind("Balance", "VanillaMinSpawnRate", 30f, "Minimum % of spawns that must remain vanilla (Level 1-3). If total custom chances exceed the remaining space, they will be scaled down proportionally. Set to 100 to disable custom spawns. Set to 0 to disable vanilla spawns"); ExcludedBiomes = plugin.Config.Bind("General", "ExcludedBiomes", "Mistlands,Ashlands", "Comma-separated list of biomes where the mod is inactive."); string text = "Deathsquito,Blob,BlobElite,BlobTar,FrostBlob,LavaBlob,Serpent,BonemawSerpent,Vulture,Skugg"; ExcludedPrefabsConfig = plugin.Config.Bind("General", "ExcludedPrefabs", text, "Comma-separated list of additional prefabs to exclude (Bosses and pets are excluded by default)."); LootBonusBlacklist = plugin.Config.Bind("Loot", "BonusBlacklist", "Coin,Stone,Resin,Wood", "Comma-separated list of item prefab names that should NEVER drop as an extra bonus item. Trophy is also excluded."); ParseConfig(); } public void ParseConfig() { excludedPrefabsSet.Clear(); string[] internalBlacklist = InternalBlacklist; foreach (string item in internalBlacklist) { excludedPrefabsSet.Add(item); } foreach (string item2 in from p in ExcludedPrefabsConfig.Value.Split(new char[1] { ',' }) select p.Trim() into p where !string.IsNullOrEmpty(p) select p) { excludedPrefabsSet.Add(item2); } lootBlacklistSet.Clear(); foreach (string item3 in from p in LootBonusBlacklist.Value.Split(new char[1] { ',' }) select p.Trim().ToLower() into p where !string.IsNullOrEmpty(p) select p) { lootBlacklistSet.Add(item3); } } public bool IsPrefabExcluded(string prefabName) { if (string.IsNullOrEmpty(prefabName)) { return false; } if (prefabName.StartsWith("Fish")) { return true; } return excludedPrefabsSet.Contains(prefabName); } public bool IsItemBlacklisted(string itemName) { if (string.IsNullOrEmpty(itemName)) { return false; } string lowerName = itemName.ToLower(); return lootBlacklistSet.Any((string b) => lowerName.Contains(b)); } public bool IsBiomeExcluded(Biome currentBiome) { string biomeStr = ((object)(Biome)(ref currentBiome)).ToString(); return ExcludedBiomes.Value.Split(new char[1] { ',' }).Any((string b) => b.Trim().Equals(biomeStr, StringComparison.OrdinalIgnoreCase)); } } } namespace KillCountEvolution.Patches { [HarmonyPatch(typeof(CharacterDrop), "GenerateDropList")] public static class DropPatch { private static bool Prefix(CharacterDrop __instance, ref List> __result) { Character component = ((Component)__instance).GetComponent(); if ((Object)(object)component == (Object)null) { return true; } int level = component.GetLevel(); if (level < 4) { return true; } MobSpawnConfig config = KillCountEvolution.Instance.mobConfig; List> list = new List>(); foreach (Drop drop in __instance.m_drops) { if ((Object)(object)drop.m_prefab == (Object)null || 1 == 0) { continue; } int num = Random.Range(drop.m_amountMin, drop.m_amountMax + 1); if (num <= 0) { continue; } if (((Object)drop.m_prefab).name.ToLower().Contains("trophy")) { if (Random.value <= drop.m_chance) { list.Add(new KeyValuePair(drop.m_prefab, num)); } } else { list.Add(new KeyValuePair(drop.m_prefab, num * 4)); } } int num2 = level switch { 6 => 2, 5 => 1, _ => 0, }; if (num2 > 0) { List list2 = (from d in __instance.m_drops where (Object)(object)d.m_prefab != (Object)null select d.m_prefab into p where !((Object)p).name.ToLower().Contains("trophy") && !config.IsItemBlacklisted(((Object)p).name) select p).ToList(); if (list2.Count > 0) { GameObject key = list2[Random.Range(0, list2.Count)]; list.Add(new KeyValuePair(key, num2)); } } __result = list; return false; } } }