using HarmonyLib; using System; using UnityEngine; namespace MuzikaGromche { [HarmonyPatch(typeof(RoundManager))] static class SpawnRatePatch { const string JesterEnemyName = "Jester"; // GetRandomWeightedIndex is not only called from AssignRandomEnemyToVent, // so in order to differentiate it from other calls, prefix assigns these // global variables, and postfix cleans them up. // If set to null, do not override spawn chances. // Otherwise, it is an index of Jester in RoundManager.currentLevel.Enemies static int? EnemyIndex = null; static float SpawnTime = 0f; [HarmonyPatch(nameof(RoundManager.AssignRandomEnemyToVent))] [HarmonyPrefix] static void AssignRandomEnemyToVentPrefix(RoundManager __instance, EnemyVent vent, float spawnTime) { if (!Config.OverrideSpawnRates.Value) { return; } var index = __instance.currentLevel.Enemies.FindIndex(enemy => enemy.enemyType.enemyName == JesterEnemyName); if (index == -1) { return; } EnemyIndex = index; SpawnTime = spawnTime; } [HarmonyPatch(nameof(RoundManager.AssignRandomEnemyToVent))] [HarmonyPostfix] static void AssignRandomEnemyToVentPostfix(RoundManager __instance, EnemyVent vent, float spawnTime) { EnemyIndex = null; SpawnTime = 0f; } [HarmonyPatch(nameof(RoundManager.GetRandomWeightedIndex))] [HarmonyPrefix] static void GetRandomWeightedIndexPostfix(RoundManager __instance, int[] weights, System.Random randomSeed) { if (EnemyIndex is int index) { if (__instance.EnemyCannotBeSpawned(index)) { return; } // 0 == 6:00 AM // 60 == 7:00 AM // 100 == 7:40 AM (Cycle #1) // 120 == 8:00 AM // 180 == 9:00 AM (Cycle #2) // 300 == 11:00 AM (Cycle #3) // 420 == 1:00 PM (Cycle #4) // 540 == 3:00 PM (Cycle #5) // 660 ~= 5:00 PM // 780 ~= 7:00 PM // 900 ~= 9:00 PM // 1020 ~= 11:00 PM // 1080 == 12:00 AM const float minMultiplierTime = 200f; // 9:20 AM const float maxMultiplierTime = 500f; // 2:00 PM var normalizedMultiplierTime = Mathf.Clamp((SpawnTime - minMultiplierTime) / (maxMultiplierTime - minMultiplierTime), 0f, 1f); // Start slowly, then escalate it quickly normalizedMultiplierTime = Easing.InCubic.Eval(normalizedMultiplierTime); const float minMultiplier = 1f; const float maxMultiplier = 15f; var multiplier = Mathf.Lerp(minMultiplier, maxMultiplier, normalizedMultiplierTime); var newWeight = Mathf.FloorToInt(weights[index] * multiplier); Debug.Log($"{nameof(MuzikaGromche)} {nameof(SpawnRatePatch)} Overriding spawn weight[{index}] {weights[index]} * {multiplier} => {newWeight} for t={SpawnTime}"); weights[index] = newWeight; } } } }