1
0
Fork 0

Add spawn rate patch to make the event more likely

This commit is contained in:
ivan tkachenko 2025-08-03 14:29:15 +03:00
parent 276fbbec22
commit 1ffdd5d97e
4 changed files with 99 additions and 0 deletions

View File

@ -5,6 +5,7 @@
- Fixed more missing flickering behaviours for some animators controllers. - Fixed more missing flickering behaviours for some animators controllers.
- Fixed some powered lights not fully turning off or flickering when there are multiple Light components per container. - Fixed some powered lights not fully turning off or flickering when there are multiple Light components per container.
- Improved performance by pre-loading certain assets at the start of round instead of at a timing-critical frame update. - Improved performance by pre-loading certain assets at the start of round instead of at a timing-critical frame update.
- Added an opt-in config option to increase certain spawn rate to experience content of this mod more often.
## MuzikaGromche 13.37.1337 - Photosensitivity Warning Edition ## MuzikaGromche 13.37.1337 - Photosensitivity Warning Edition

View File

@ -553,6 +553,7 @@ namespace MuzikaGromche
harmony.PatchAll(typeof(AllPoweredLightsPatch)); harmony.PatchAll(typeof(AllPoweredLightsPatch));
harmony.PatchAll(typeof(DiscoBallTilePatch)); harmony.PatchAll(typeof(DiscoBallTilePatch));
harmony.PatchAll(typeof(DiscoBallDespawnPatch)); harmony.PatchAll(typeof(DiscoBallDespawnPatch));
harmony.PatchAll(typeof(SpawnRatePatch));
} }
else else
{ {
@ -1427,6 +1428,8 @@ namespace MuzikaGromche
public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null!; public static ConfigEntry<bool> SkipExplicitTracks { get; private set; } = null!;
public static SyncedEntry<bool> OverrideSpawnRates { get; private set; } = null!;
public static bool ShouldSkipWindingPhase { get; private set; } = false; public static bool ShouldSkipWindingPhase { get; private set; } = false;
public static Palette? PaletteOverride { get; private set; } = null; public static Palette? PaletteOverride { get; private set; } = null;
@ -1455,6 +1458,11 @@ namespace MuzikaGromche
new ConfigDescription("When choosing tracks at random, skip the ones with Explicit Content/Lyrics.")); new ConfigDescription("When choosing tracks at random, skip the ones with Explicit Content/Lyrics."));
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(SkipExplicitTracks, requiresRestart: false)); LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(SkipExplicitTracks, requiresRestart: false));
OverrideSpawnRates = configFile.BindSyncedEntry("General", "Override Spawn Rates", false,
new ConfigDescription("Deviate from vanilla spawn rates to experience content of this mod more often."));
LethalConfigManager.AddConfigItem(new BoolCheckBoxConfigItem(OverrideSpawnRates.Entry, Default(new BoolCheckBoxOptions())));
CSyncHackAddSyncedEntry(OverrideSpawnRates);
#if DEBUG #if DEBUG
SetupEntriesToSkipWinding(configFile); SetupEntriesToSkipWinding(configFile);
SetupEntriesForPaletteOverride(configFile); SetupEntriesForPaletteOverride(configFile);

View File

@ -0,0 +1,88 @@
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;
}
}
}
}

View File

@ -17,6 +17,8 @@ Speaking of dependencies, [`V70PoweredLights_Fix`] is not strictly required, but
Configuration integrates with [`LethalConfig`] mod. Configuration integrates with [`LethalConfig`] mod.
If you are just trying out this mod for the first time, or want to experience it more often, consider toggling ON the "Override Spawn Rates" config entry. Otherwise it might take a frustratingly long time to find out what you need to find out.
Track selection options are only configurable by host player and only while orbiting. Track selection options are only configurable by host player and only while orbiting.
Any player can change their personal preferences locally. Any player can change their personal preferences locally.