forked from nikita/muzika-gromche
Compare commits
No commits in common. "dev" and "master" have entirely different histories.
|
@ -1,5 +0,0 @@
|
||||||
[*.cs]
|
|
||||||
|
|
||||||
# IDE0290: Use primary constructor
|
|
||||||
# Primary constructors are far from perfect: they can't have readonly fields, while fields can be used anywhere in the class body.
|
|
||||||
csharp_style_prefer_primary_constructors = false
|
|
BIN
Assets/BeefLiverIntro.ogg (Stored with Git LFS)
BIN
Assets/BeefLiverIntro.ogg (Stored with Git LFS)
Binary file not shown.
BIN
Assets/BeefLiverLoop.ogg (Stored with Git LFS)
BIN
Assets/BeefLiverLoop.ogg (Stored with Git LFS)
Binary file not shown.
BIN
Assets/Beha1Intro.ogg (Stored with Git LFS)
BIN
Assets/Beha1Intro.ogg (Stored with Git LFS)
Binary file not shown.
BIN
Assets/Beha2Intro.ogg (Stored with Git LFS)
BIN
Assets/Beha2Intro.ogg (Stored with Git LFS)
Binary file not shown.
BIN
Assets/Beha3Intro.ogg (Stored with Git LFS)
BIN
Assets/Beha3Intro.ogg (Stored with Git LFS)
Binary file not shown.
BIN
Assets/BehaLoop.ogg (Stored with Git LFS)
BIN
Assets/BehaLoop.ogg (Stored with Git LFS)
Binary file not shown.
33
CHANGELOG.md
33
CHANGELOG.md
|
@ -1,38 +1,5 @@
|
||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
## MuzikaGromche 1337.420.9001 - Multiverse Edition
|
|
||||||
|
|
||||||
- Added support for tracks to rotate between multiple audio variants during a round.
|
|
||||||
- Added a new track Beha with three different variants of intro.
|
|
||||||
|
|
||||||
## MuzikaGromche 1337.420.69 - It's All DiscoNnected Edition
|
|
||||||
|
|
||||||
- Fixed harmless but annoying errors in BepInEx console output.
|
|
||||||
- Improve smoothness of color animations.
|
|
||||||
- Added a new track BeefLiver.
|
|
||||||
|
|
||||||
## MuzikaGromche 1337.69.420 - It's All Connected Edition
|
|
||||||
|
|
||||||
- Fix certain object hanging around after being disabled.
|
|
||||||
- CSync proved to be unreliable for config syncing, so rewrote track selection to custom netcode.
|
|
||||||
|
|
||||||
## MuzikaGromche 13.37.9001 - Chromaberrated Edition
|
|
||||||
|
|
||||||
- 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.
|
|
||||||
- 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
|
|
||||||
|
|
||||||
- Added LobbyCompatibility to dependencies to avoid desync issues.
|
|
||||||
- Fixed lyrics not being displayed in some situations.
|
|
||||||
- Fixed visual issues with the fade out effect.
|
|
||||||
- Fixed visual glitch at the last beat of a loop.
|
|
||||||
- Fixed timings of one of the tracks.
|
|
||||||
- Removed unnecessary "Enable Color Animations" config option.
|
|
||||||
- Fixed missing flickering behaviours for some animators controllers.
|
|
||||||
|
|
||||||
## MuzikaGromche 13.37.911 - Sri Lanka Bus hotfix
|
## MuzikaGromche 13.37.911 - Sri Lanka Bus hotfix
|
||||||
|
|
||||||
- Fixed certain event sometimes not working due to wrong method call.
|
- Fixed certain event sometimes not working due to wrong method call.
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
<Project>
|
|
||||||
<Target Name="NetcodePatch" AfterTargets="PostBuildEvent">
|
|
||||||
<Exec Command="dotnet netcode-patch -nv 1.5.2 "$(TargetPath)" @(ReferencePathWithRefAssemblies->'"%(Identity)"', ' ')"/>
|
|
||||||
</Target>
|
|
||||||
</Project>
|
|
2
Justfile
2
Justfile
|
@ -11,7 +11,7 @@ build-debug:
|
||||||
clean:
|
clean:
|
||||||
rm -rf dist MuzikaGromche/bin MuzikaGromche/obj
|
rm -rf dist MuzikaGromche/bin MuzikaGromche/obj
|
||||||
|
|
||||||
plugin_dir := "$HOME/.config/r2modmanPlus-local/LethalCompany/profiles" / imperium_profile / "BepInEx/plugins/Ratijas-MuzikaGromche/"
|
plugin_dir := "$HOME/.config/r2modmanPlus-local/LethalCompany/profiles" / imperium_profile / "BepInEx/plugins/Oflor-MuzikaGromche/"
|
||||||
|
|
||||||
install-imperium:
|
install-imperium:
|
||||||
rm -rf "{{ plugin_dir }}"
|
rm -rf "{{ plugin_dir }}"
|
||||||
|
|
|
@ -1,6 +1,4 @@
|
||||||
using DunGen;
|
using DunGen;
|
||||||
using HarmonyLib;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
@ -9,21 +7,54 @@ using UnityEngine;
|
||||||
|
|
||||||
namespace MuzikaGromche
|
namespace MuzikaGromche
|
||||||
{
|
{
|
||||||
public static class DiscoBallManager
|
public class DiscoBallManager : MonoBehaviour
|
||||||
{
|
{
|
||||||
// A struct holding a disco ball container object and the name of a tile for which it was designed.
|
// A struct holding a disco ball container object and the name of a tile for which it was designed.
|
||||||
private readonly record struct TilePatch(string TileName, GameObject DiscoBallContainer)
|
public readonly record struct Data(string TileName, GameObject DiscoBallContainer)
|
||||||
{
|
{
|
||||||
// We are specifically looking for cloned tiles, not the original prototypes.
|
// We are specifically looking for cloned tiles, not the original prototypes.
|
||||||
public readonly string TileCloneName = $"{TileName}(Clone)";
|
public readonly string TileCloneName = $"{TileName}(Clone)";
|
||||||
}
|
}
|
||||||
|
|
||||||
private static TilePatch[] Patches = [];
|
public static readonly List<Data> Containers = [];
|
||||||
|
private static readonly List<GameObject> InstantiatedContainers = [];
|
||||||
|
|
||||||
private static readonly List<GameObject> CachedDiscoBalls = [];
|
public static void Initialize()
|
||||||
private static readonly List<Animator> CachedDiscoBallAnimators = [];
|
{
|
||||||
|
string assetdir = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "muzikagromche");
|
||||||
|
var bundle = AssetBundle.LoadFromFile(assetdir);
|
||||||
|
|
||||||
private static readonly string[] AnimatorContainersNames = [
|
foreach ((string prefabPath, string tileName) in new[] {
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManor.prefab", "ManorStartRoomSmall"),
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManorOLD.prefab", "ManorStartRoom"),
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerFactory.prefab", "StartRoom"),
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerMineShaft.prefab", "MineshaftStartTile"),
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerLargeForkTileB.prefab", "LargeForkTileB"),
|
||||||
|
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerBirthdayRoomTile.prefab", "BirthdayRoomTile"),
|
||||||
|
})
|
||||||
|
{
|
||||||
|
var container = bundle.LoadAsset<GameObject>(prefabPath);
|
||||||
|
Containers.Add(new(tileName, container));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Enable()
|
||||||
|
{
|
||||||
|
// Just in case
|
||||||
|
Disable();
|
||||||
|
|
||||||
|
var query = from tile in Resources.FindObjectsOfTypeAll<Tile>()
|
||||||
|
join container in Containers
|
||||||
|
on tile.gameObject.name equals container.TileCloneName
|
||||||
|
select (tile, container);
|
||||||
|
|
||||||
|
foreach (var (tile, container) in query)
|
||||||
|
{
|
||||||
|
Enable(tile, container);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly string[] animatorNames = [
|
||||||
"DiscoBallProp/AnimContainer",
|
"DiscoBallProp/AnimContainer",
|
||||||
"DiscoBallProp1/AnimContainer",
|
"DiscoBallProp1/AnimContainer",
|
||||||
"DiscoBallProp2/AnimContainer",
|
"DiscoBallProp2/AnimContainer",
|
||||||
|
@ -32,134 +63,29 @@ namespace MuzikaGromche
|
||||||
"DiscoBallProp5/AnimContainer",
|
"DiscoBallProp5/AnimContainer",
|
||||||
];
|
];
|
||||||
|
|
||||||
public static void Load()
|
private static void Enable(Tile tile, Data container)
|
||||||
{
|
{
|
||||||
const string BundleFileName = "muzikagromche_discoball";
|
Debug.Log($"{nameof(MuzikaGromche)} {nameof(DiscoBallManager)} Enabling at '{tile.gameObject.name}'");
|
||||||
string bundlePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundleFileName);
|
var discoBall = Instantiate(container.DiscoBallContainer, tile.transform);
|
||||||
var assetBundle = AssetBundle.LoadFromFile(bundlePath)
|
InstantiatedContainers.Add(discoBall);
|
||||||
?? throw new NullReferenceException("Failed to load bundle");
|
|
||||||
|
|
||||||
(string PrefabPath, string TileName)[] patchDescriptors =
|
foreach (var animatorName in animatorNames)
|
||||||
[
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManor.prefab", "ManorStartRoomSmall"),
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerManorOLD.prefab", "ManorStartRoom"),
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerFactory.prefab", "StartRoom"),
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerMineShaft.prefab", "MineshaftStartTile"),
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerLargeForkTileB.prefab", "LargeForkTileB"),
|
|
||||||
("Assets/LethalCompany/Mods/MuzikaGromche/DiscoBallContainerBirthdayRoomTile.prefab", "BirthdayRoomTile"),
|
|
||||||
];
|
|
||||||
|
|
||||||
Patches = [.. patchDescriptors.Select(d =>
|
|
||||||
new TilePatch(d.TileName, assetBundle.LoadAsset<GameObject>(d.PrefabPath))
|
|
||||||
)];
|
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Patch(Tile tile)
|
|
||||||
{
|
{
|
||||||
var query = from patch in Patches
|
if (discoBall.transform.Find(animatorName)?.gameObject is GameObject animator)
|
||||||
where tile.gameObject.name == patch.TileCloneName
|
|
||||||
select patch;
|
|
||||||
|
|
||||||
// Should be just one, but FirstOrDefault() isn't usable with structs
|
|
||||||
foreach (var patch in query)
|
|
||||||
{
|
{
|
||||||
Patch(tile, patch);
|
animator.GetComponent<Animator>().SetBool("on", true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void Patch(Tile tile, TilePatch patch)
|
|
||||||
{
|
|
||||||
var discoBall = UnityEngine.Object.Instantiate(patch.DiscoBallContainer, tile.transform);
|
|
||||||
if (discoBall == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var animator in FindDiscoBallAnimators(discoBall))
|
|
||||||
{
|
|
||||||
CachedDiscoBallAnimators.Add(animator);
|
|
||||||
}
|
|
||||||
CachedDiscoBalls.Add(discoBall);
|
|
||||||
discoBall.SetActive(false);
|
|
||||||
|
|
||||||
Debug.Log($"{nameof(MuzikaGromche)} {nameof(DiscoBallManager)} Patched tile '{tile.gameObject.name}'");
|
|
||||||
}
|
|
||||||
|
|
||||||
static IEnumerable<Animator> FindDiscoBallAnimators(GameObject discoBall)
|
|
||||||
{
|
|
||||||
foreach (var animatorContainerName in AnimatorContainersNames)
|
|
||||||
{
|
|
||||||
var transform = discoBall.transform.Find(animatorContainerName);
|
|
||||||
if (transform == null)
|
|
||||||
{
|
|
||||||
// Not all prefabs have all possible animators, and it's OK
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
var animator = transform.gameObject?.GetComponent<Animator>();
|
|
||||||
if (animator == null)
|
|
||||||
{
|
|
||||||
// This would be weird
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
yield return animator;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Toggle(bool on)
|
|
||||||
{
|
|
||||||
Debug.Log($"{nameof(MuzikaGromche)} {nameof(DiscoBallManager)} Toggle {(on ? "ON" : "OFF")} {CachedDiscoBallAnimators.Count} animators");
|
|
||||||
|
|
||||||
foreach (var discoBall in CachedDiscoBalls)
|
|
||||||
{
|
|
||||||
discoBall.SetActive(on);
|
|
||||||
}
|
|
||||||
foreach (var animator in CachedDiscoBallAnimators)
|
|
||||||
{
|
|
||||||
animator?.SetBool("on", on);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Enable()
|
|
||||||
{
|
|
||||||
Toggle(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Disable()
|
public static void Disable()
|
||||||
{
|
{
|
||||||
Toggle(false);
|
foreach (var discoBall in InstantiatedContainers)
|
||||||
}
|
|
||||||
|
|
||||||
internal static void Clear()
|
|
||||||
{
|
{
|
||||||
Debug.Log($"{nameof(MuzikaGromche)} {nameof(DiscoBallManager)} Clearing {CachedDiscoBalls.Count} disco balls & {CachedDiscoBallAnimators.Count} animators");
|
Debug.Log($"{nameof(MuzikaGromche)} {nameof(DiscoBallManager)}: Disabling {discoBall.name}");
|
||||||
CachedDiscoBallAnimators.Clear();
|
Destroy(discoBall);
|
||||||
CachedDiscoBalls.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
InstantiatedContainers.Clear();
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Tile))]
|
|
||||||
static class DiscoBallTilePatch
|
|
||||||
{
|
|
||||||
[HarmonyPatch(nameof(Tile.AddTriggerVolume))]
|
|
||||||
[HarmonyPostfix]
|
|
||||||
static void OnAddTriggerVolume(Tile __instance)
|
|
||||||
{
|
|
||||||
DiscoBallManager.Patch(__instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(RoundManager))]
|
|
||||||
static class DiscoBallDespawnPatch
|
|
||||||
{
|
|
||||||
[HarmonyPatch(nameof(RoundManager.DespawnPropsAtEndOfRound))]
|
|
||||||
[HarmonyPatch(nameof(RoundManager.OnDestroy))]
|
|
||||||
[HarmonyPrefix]
|
|
||||||
static void OnDestroy(RoundManager __instance)
|
|
||||||
{
|
|
||||||
var _ = __instance;
|
|
||||||
DiscoBallManager.Clear();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,66 +2,41 @@
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.1</TargetFramework>
|
<TargetFramework>netstandard2.1</TargetFramework>
|
||||||
<Title>MuzikaGromche</Title>
|
<AssemblyName>MuzikaGromche</AssemblyName>
|
||||||
<PackageId>MuzikaGromche</PackageId>
|
<Description>Opa che tut u nas</Description>
|
||||||
<RootNamespace>MuzikaGromche</RootNamespace>
|
<Version>13.37.911</Version>
|
||||||
<AssemblyName>Ratijas.MuzikaGromche</AssemblyName>
|
|
||||||
<Product>Muzika Gromche</Product>
|
|
||||||
<Description>Add some content to your inverse teleporter experience on Titan!</Description>
|
|
||||||
<Version>1337.420.9001</Version>
|
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<LangVersion>latest</LangVersion>
|
<LangVersion>latest</LangVersion>
|
||||||
<Nullable>enable</Nullable>
|
|
||||||
|
|
||||||
<!-- NetcodePatch requires anything but 'full' -->
|
|
||||||
<DebugType>portable</DebugType>
|
|
||||||
|
|
||||||
<PackageReadmeFile>../README.md</PackageReadmeFile>
|
|
||||||
<PackageProjectUrl>https://git.vilunov.me/ratijas/muzika-gromche</PackageProjectUrl>
|
|
||||||
<RepositoryUrl>https://git.vilunov.me/ratijas/muzika-gromche</RepositoryUrl>
|
|
||||||
<RepositoryType>git</RepositoryType>
|
|
||||||
|
|
||||||
<!-- NuGet Information -->
|
|
||||||
<RestoreAdditionalProjectSources>
|
|
||||||
https://api.nuget.org/v3/index.json;
|
|
||||||
https://nuget.bepinex.dev/v3/index.json;
|
|
||||||
https://nuget.windows10ce.com/nuget/v3/index.json
|
|
||||||
</RestoreAdditionalProjectSources>
|
|
||||||
|
|
||||||
<!-- Prevent Publicizer Warnings from Showing -->
|
|
||||||
<NoWarn>$(NoWarn);CS0436</NoWarn>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all" Private="false" />
|
<PackageReference Include="BepInEx.Analyzers" Version="1.*" PrivateAssets="all"/>
|
||||||
<PackageReference Include="BepInEx.Core" Version="5.*" PrivateAssets="all" Private="false" />
|
<PackageReference Include="BepInEx.Core" Version="5.*"/>
|
||||||
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*" PrivateAssets="all" Private="false" />
|
<PackageReference Include="BepInEx.PluginInfoProps" Version="1.*"/>
|
||||||
<PackageReference Include="UnityEngine.Modules" Version="2022.3.9" PrivateAssets="all" Private="false" />
|
<PackageReference Include="UnityEngine.Modules" Version="2022.3.9" IncludeAssets="compile"/>
|
||||||
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.1" PrivateAssets="all" Private="false" />
|
<PackageReference Include="BepInEx.AssemblyPublicizer.MSBuild" Version="0.4.1" PrivateAssets="all" />
|
||||||
<!--
|
<!--
|
||||||
Publicize internal methods, so we could generate config entries for tracks at runtime instead
|
Publicize internal methods, so we could generate config entries for tracks at runtime instead
|
||||||
of generating code at compile time. See https://github.com/lc-sigurd/CSync/issues/11
|
of generating code at compile time. See https://github.com/lc-sigurd/CSync/issues/11
|
||||||
It is an optional dependency now, but there is no sane way to mark it as such.
|
|
||||||
-->
|
-->
|
||||||
<PackageReference Include="Sigurd.BepInEx.CSync" Version="5.0.1" Publicize="true" PrivateAssets="all" Private="false" />
|
<PackageReference Include="Sigurd.BepInEx.CSync" Version="5.0.1" Publicize="true" />
|
||||||
<PackageReference Include="AinaVT-LethalConfig" Version="1.4.6" PrivateAssets="all" Private="false" />
|
<PackageReference Include="AinaVT-LethalConfig" Version="1.4.6" />
|
||||||
<PackageReference Include="TeamBMX.LobbyCompatibility" Version="1.*" PrivateAssets="all" Private="false" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Reference Include="Assembly-CSharp" Publicize="true" Private="false">
|
<Reference Include="Assembly-CSharp" Publicize="true">
|
||||||
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Assembly-CSharp.dll</HintPath>
|
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Assembly-CSharp.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Unity.Collections" Private="false">
|
<Reference Include="Unity.Collections">
|
||||||
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Collections.dll</HintPath>
|
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Collections.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
<Reference Include="Unity.Netcode.Runtime" Publicize="true" Private="false">
|
<Reference Include="Unity.Netcode.Runtime" Publicize="true">
|
||||||
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll</HintPath>
|
<HintPath>$(LethalCompanyDir)Lethal Company_Data\Managed\Unity.Netcode.Runtime.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
<ItemGroup Condition="'$(TargetFramework.TrimEnd(`0123456789`))' == 'net'">
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="all" Private="false" />
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.2" PrivateAssets="all"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<Target Name="Bundle" AfterTargets="Build">
|
<Target Name="Bundle" AfterTargets="Build">
|
||||||
|
@ -72,12 +47,10 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackagedResources Include="$(SolutionDir)README.md" />
|
<PackagedResources Include="$(SolutionDir)README.md" />
|
||||||
<PackagedResources Include="$(SolutionDir)CHANGELOG.md" />
|
|
||||||
<PackagedResources Include="$(SolutionDir)icon.png" />
|
<PackagedResources Include="$(SolutionDir)icon.png" />
|
||||||
<PackagedResources Include="$(SolutionDir)manifest.json" />
|
<PackagedResources Include="$(SolutionDir)manifest.json" />
|
||||||
<PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche_discoball" />
|
<PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche" />
|
||||||
<PackagedResources Include="$(ProjectDir)UnityAssets\muzikagromche_poweredlightsanimators" />
|
<PackagedResources Include="$(TargetDir)MuzikaGromche.dll" />
|
||||||
<PackagedResources Include="$(TargetDir)$(AssemblyName).dll" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
@ -110,9 +83,9 @@
|
||||||
-->
|
-->
|
||||||
<Target Name="wav2ogg">
|
<Target Name="wav2ogg">
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<TrackNames Include="$(TrackName)Intro" />
|
<TrackNames Include="$(TrackName)Start" />
|
||||||
<TrackNames Include="$(TrackName)Loop" />
|
<TrackNames Include="$(TrackName)Loop" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Exec Command="ffmpeg -bitexact -y -i $(WavExportDir)%(TrackNames.Identity).wav $(SolutionDir)Assets\%(TrackNames.Identity).ogg" />
|
<Exec Command="ffmpeg -bitexact -y -i $(WavExportDir)%(TrackNames.Identity).wav $(SolutionDir)Assets\%(TrackNames.Identity).ogg"/>
|
||||||
</Target>
|
</Target>
|
||||||
</Project>
|
</Project>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,290 +0,0 @@
|
||||||
using DunGen;
|
|
||||||
using HarmonyLib;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reflection;
|
|
||||||
using UnityEngine;
|
|
||||||
|
|
||||||
namespace MuzikaGromche
|
|
||||||
{
|
|
||||||
static class PoweredLightsAnimators
|
|
||||||
{
|
|
||||||
private const string PoweredLightTag = "PoweredLight";
|
|
||||||
|
|
||||||
private delegate void ManualPatch(GameObject animatorContainer);
|
|
||||||
|
|
||||||
private readonly record struct AnimatorPatch(
|
|
||||||
string AnimatorContainerPath,
|
|
||||||
RuntimeAnimatorController AnimatorController,
|
|
||||||
bool AddTagAndAnimator,
|
|
||||||
ManualPatch? ManualPatch);
|
|
||||||
|
|
||||||
private readonly record struct TilePatch(string TileName, AnimatorPatch[] Patches)
|
|
||||||
{
|
|
||||||
// We are specifically looking for cloned tiles, not the original prototypes.
|
|
||||||
public readonly string TileCloneName = $"{TileName}(Clone)";
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly record struct AnimatorPatchDescriptor(
|
|
||||||
string AnimatorContainerPath,
|
|
||||||
string AnimatorControllerAssetPath,
|
|
||||||
bool AddTagAndAnimator = false,
|
|
||||||
ManualPatch? ManualPatch = null)
|
|
||||||
{
|
|
||||||
public AnimatorPatch Load(AssetBundle assetBundle)
|
|
||||||
{
|
|
||||||
var animationController = assetBundle.LoadAsset<RuntimeAnimatorController>(AnimatorControllerAssetPath)
|
|
||||||
?? throw new FileNotFoundException($"RuntimeAnimatorController not found: {AnimatorControllerAssetPath}", AnimatorControllerAssetPath);
|
|
||||||
return new(AnimatorContainerPath, animationController, AddTagAndAnimator, ManualPatch);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly record struct TilePatchDescriptor(string[] TileNames, AnimatorPatchDescriptor[] Descriptors)
|
|
||||||
{
|
|
||||||
public TilePatchDescriptor(string TileName, AnimatorPatchDescriptor[] Descriptors)
|
|
||||||
: this([TileName], Descriptors)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public TilePatch[] Load(AssetBundle assetBundle)
|
|
||||||
{
|
|
||||||
var patches = Descriptors.Select(d => d.Load(assetBundle)).ToArray();
|
|
||||||
return [.. TileNames.Select(tileName => new TilePatch(tileName, patches))];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static IDictionary<string, TilePatch> Patches = new Dictionary<string, TilePatch>();
|
|
||||||
|
|
||||||
private static AudioClip AudioClipOn = null!;
|
|
||||||
private static AudioClip AudioClipOff = null!;
|
|
||||||
private static AudioClip AudioClipFlicker = null!;
|
|
||||||
|
|
||||||
public static void Load()
|
|
||||||
{
|
|
||||||
const string BundleFileName = "muzikagromche_poweredlightsanimators";
|
|
||||||
string bundlePath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), BundleFileName);
|
|
||||||
var assetBundle = AssetBundle.LoadFromFile(bundlePath)
|
|
||||||
?? throw new NullReferenceException("Failed to load bundle");
|
|
||||||
|
|
||||||
AudioClipOn = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightOn.ogg");
|
|
||||||
AudioClipOff = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightOff.ogg");
|
|
||||||
AudioClipFlicker = assetBundle.LoadAsset<AudioClip>("Assets/LethalCompany/Mods/MuzikaGromche/AudioClips/LightFlicker.ogg");
|
|
||||||
|
|
||||||
const string BasePath = "Assets/LethalCompany/Mods/MuzikaGromche/AnimatorControllers/";
|
|
||||||
|
|
||||||
const string PointLight4 = $"{BasePath}Point Light (4) (Patched).controller";
|
|
||||||
const string MineshaftSpotlight = $"{BasePath}MineshaftSpotlight (Patched).controller";
|
|
||||||
const string LightbulbsLine = $"{BasePath}lightbulbsLineMesh (Patched).controller";
|
|
||||||
const string CeilingFan = $"{BasePath}CeilingFan (originally GameObject) (Patched).controller";
|
|
||||||
const string LEDHangingLight = $"{BasePath}LEDHangingLight (Patched).controller";
|
|
||||||
const string MineshaftStartTileSpotlight = $"{BasePath}MineshaftStartTileSpotlight (New).controller";
|
|
||||||
|
|
||||||
TilePatchDescriptor[] descriptors =
|
|
||||||
[
|
|
||||||
// any version
|
|
||||||
new("KitchenTile", [
|
|
||||||
new("PoweredLightTypeB", PointLight4),
|
|
||||||
new("PoweredLightTypeB (1)", PointLight4),
|
|
||||||
]),
|
|
||||||
// < v70
|
|
||||||
new("ManorStartRoom", [
|
|
||||||
new("ManorStartRoom/Chandelier/PoweredLightTypeB (1)", PointLight4),
|
|
||||||
new("ManorStartRoom/Chandelier2/PoweredLightTypeB", PointLight4),
|
|
||||||
]),
|
|
||||||
// v70+
|
|
||||||
new("ManorStartRoomSmall", [
|
|
||||||
new("ManorStartRoomMesh/Chandelier/PoweredLightTypeB (1)", PointLight4),
|
|
||||||
new("ManorStartRoomMesh/Chandelier2/PoweredLightTypeB", PointLight4),
|
|
||||||
]),
|
|
||||||
new("NarrowHallwayTile2x2", [
|
|
||||||
new("MineshaftSpotlight (1)", MineshaftSpotlight),
|
|
||||||
new("MineshaftSpotlight (2)", MineshaftSpotlight),
|
|
||||||
]),
|
|
||||||
new("BirthdayRoomTile", [
|
|
||||||
new("Lights/MineshaftSpotlight", MineshaftSpotlight),
|
|
||||||
]),
|
|
||||||
new("BathroomTileContainer", [
|
|
||||||
new("MineshaftSpotlight", MineshaftSpotlight),
|
|
||||||
new("LightbulbLine/lightbulbsLineMesh", LightbulbsLine),
|
|
||||||
]),
|
|
||||||
new(["BedroomTile", "BedroomTileB"], [
|
|
||||||
new("CeilingFanAnimContainer", CeilingFan),
|
|
||||||
new("MineshaftSpotlight (1)", MineshaftSpotlight),
|
|
||||||
]),
|
|
||||||
new("GarageTile", [
|
|
||||||
new("HangingLEDBarLight (3)", LEDHangingLight),
|
|
||||||
new("HangingLEDBarLight (4)", LEDHangingLight,
|
|
||||||
// This HangingLEDBarLight's IndirectLight is wrongly named, so animator couldn't find it
|
|
||||||
ManualPatch: RenameGameObjectPatch("IndirectLight (1)", "IndirectLight")),
|
|
||||||
]),
|
|
||||||
new("PoolTile", [
|
|
||||||
new("PoolLights/HangingLEDBarLight", LEDHangingLight),
|
|
||||||
new("PoolLights/HangingLEDBarLight (4)", LEDHangingLight),
|
|
||||||
new("PoolLights/HangingLEDBarLight (5)", LEDHangingLight),
|
|
||||||
]),
|
|
||||||
new("MineshaftStartTile", [
|
|
||||||
new("Cylinder.001 (1)", MineshaftStartTileSpotlight, AddTagAndAnimator: true),
|
|
||||||
new("Cylinder.001 (2)", MineshaftStartTileSpotlight, AddTagAndAnimator: true),
|
|
||||||
]),
|
|
||||||
];
|
|
||||||
|
|
||||||
Patches = descriptors
|
|
||||||
.SelectMany(d => d.Load(assetBundle))
|
|
||||||
.ToDictionary(d => d.TileCloneName, d => d);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Patch(Tile tile)
|
|
||||||
{
|
|
||||||
if (tile == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(tile));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Patches.TryGetValue(tile.gameObject.name, out var tilePatch))
|
|
||||||
{
|
|
||||||
foreach (var patch in tilePatch.Patches)
|
|
||||||
{
|
|
||||||
Transform animationContainerTransform = tile.gameObject.transform.Find(patch.AnimatorContainerPath);
|
|
||||||
if (animationContainerTransform == null)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
throw new NullReferenceException($"{tilePatch.TileName}/{patch.AnimatorContainerPath} Animation Container not found");
|
|
||||||
#endif
|
|
||||||
#pragma warning disable CS0162 // Unreachable code detected
|
|
||||||
continue;
|
|
||||||
#pragma warning restore CS0162 // Unreachable code detected
|
|
||||||
}
|
|
||||||
|
|
||||||
GameObject animationContainer = animationContainerTransform.gameObject;
|
|
||||||
Animator animator = animationContainer.GetComponent<Animator>();
|
|
||||||
|
|
||||||
if (patch.AddTagAndAnimator)
|
|
||||||
{
|
|
||||||
animationContainer.tag = PoweredLightTag;
|
|
||||||
if (animator == null)
|
|
||||||
{
|
|
||||||
animator = animationContainer.AddComponent<Animator>();
|
|
||||||
}
|
|
||||||
if (!animationContainer.TryGetComponent<PlayAudioAnimationEvent>(out var audioScript))
|
|
||||||
{
|
|
||||||
audioScript = animationContainer.AddComponent<PlayAudioAnimationEvent>();
|
|
||||||
audioScript.audioClip = AudioClipOn;
|
|
||||||
audioScript.audioClip2 = AudioClipOff;
|
|
||||||
audioScript.audioClip3 = AudioClipFlicker;
|
|
||||||
}
|
|
||||||
if (!animationContainer.TryGetComponent<AudioSource>(out var audioSource))
|
|
||||||
{
|
|
||||||
// Copy from an existing AudioSource of another light animator
|
|
||||||
var otherSource = tile.gameObject.GetComponentInChildren<AudioSource>();
|
|
||||||
if (otherSource != null)
|
|
||||||
{
|
|
||||||
audioSource = animationContainer.AddComponent<AudioSource>();
|
|
||||||
audioSource.spatialBlend = 1;
|
|
||||||
audioSource.playOnAwake = false;
|
|
||||||
audioSource.outputAudioMixerGroup = otherSource.outputAudioMixerGroup;
|
|
||||||
audioSource.spread = otherSource.spread;
|
|
||||||
audioSource.rolloffMode = otherSource.rolloffMode;
|
|
||||||
audioSource.maxDistance = otherSource.maxDistance;
|
|
||||||
audioSource.SetCustomCurve(AudioSourceCurveType.CustomRolloff, otherSource.GetCustomCurve(AudioSourceCurveType.CustomRolloff));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (animator == null)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
throw new NullReferenceException($"{tilePatch.TileName}/{patch.AnimatorContainerPath} Animation Component not found");
|
|
||||||
#endif
|
|
||||||
#pragma warning disable CS0162 // Unreachable code detected
|
|
||||||
continue;
|
|
||||||
#pragma warning restore CS0162 // Unreachable code detected
|
|
||||||
}
|
|
||||||
|
|
||||||
patch.ManualPatch?.Invoke(animationContainer);
|
|
||||||
|
|
||||||
animator.runtimeAnimatorController = patch.AnimatorController;
|
|
||||||
Debug.Log($"{nameof(MuzikaGromche)} {nameof(PoweredLightsAnimatorsPatch)} {tilePatch.TileName}/{patch.AnimatorContainerPath}: Replaced animator controller");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ManualPatch RenameGameObjectPatch(string relativePath, string newName) => animatorContainer =>
|
|
||||||
{
|
|
||||||
var targetObject = animatorContainer.transform.Find(relativePath)?.gameObject;
|
|
||||||
if (targetObject == null)
|
|
||||||
{
|
|
||||||
#if DEBUG
|
|
||||||
throw new NullReferenceException($"{animatorContainer.name}/{relativePath}: GameObject not found!");
|
|
||||||
#endif
|
|
||||||
#pragma warning disable CS0162 // Unreachable code detected
|
|
||||||
return;
|
|
||||||
#pragma warning restore CS0162 // Unreachable code detected
|
|
||||||
}
|
|
||||||
targetObject.name = newName;
|
|
||||||
Debug.Log($"{nameof(MuzikaGromche)} {nameof(PoweredLightsAnimatorsPatch)} {animatorContainer.name}/{relativePath}: Renamed GameObject");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(Tile))]
|
|
||||||
static class PoweredLightsAnimatorsPatch
|
|
||||||
{
|
|
||||||
[HarmonyPatch(nameof(Tile.AddTriggerVolume))]
|
|
||||||
[HarmonyPostfix]
|
|
||||||
static void OnAddTriggerVolume(Tile __instance)
|
|
||||||
{
|
|
||||||
PoweredLightsAnimators.Patch(__instance);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(RoundManager))]
|
|
||||||
static class AllPoweredLightsPatch
|
|
||||||
{
|
|
||||||
// Vanilla method assumes that GameObjects with tag "PoweredLight" only contain a single Light component each.
|
|
||||||
// This is, however, not true for certains double-light setups, such as:
|
|
||||||
// - double PointLight (even though one of them is 'Point' another is 'Spot') inside CeilingFanAnimContainer in BedroomTile/BedroomTileB;
|
|
||||||
// - MineshaftSpotlight when it has not only `Point Light` but also `IndirectLight` in BirthdayRoomTile;
|
|
||||||
// - (maybe more?)
|
|
||||||
// In order to fix that, replace singular GetComponentInChildren<Light> with plural GetComponentsInChildren<Light> version.
|
|
||||||
[HarmonyPatch(nameof(RoundManager.RefreshLightsList))]
|
|
||||||
[HarmonyPrefix]
|
|
||||||
static bool OnRefreshLightsList(RoundManager __instance)
|
|
||||||
{
|
|
||||||
RefreshLightsListPatched(__instance);
|
|
||||||
// Skip the original method
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void RefreshLightsListPatched(RoundManager self)
|
|
||||||
{
|
|
||||||
// Reusable list to reduce allocations
|
|
||||||
List<Light> lights = [];
|
|
||||||
|
|
||||||
self.allPoweredLights.Clear();
|
|
||||||
self.allPoweredLightsAnimators.Clear();
|
|
||||||
|
|
||||||
GameObject[] gameObjects = GameObject.FindGameObjectsWithTag("PoweredLight");
|
|
||||||
if (gameObjects == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var gameObject in gameObjects)
|
|
||||||
{
|
|
||||||
Animator animator = gameObject.GetComponentInChildren<Animator>();
|
|
||||||
if (!(animator == null))
|
|
||||||
{
|
|
||||||
self.allPoweredLightsAnimators.Add(animator);
|
|
||||||
// Patched section: Use list instead of singular GetComponentInChildren<Light>
|
|
||||||
gameObject.GetComponentsInChildren(includeInactive: true, lights);
|
|
||||||
self.allPoweredLights.AddRange(lights);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
foreach (var animator in self.allPoweredLightsAnimators)
|
|
||||||
{
|
|
||||||
animator.SetFloat("flickerSpeed", UnityEngine.Random.Range(0.6f, 1.4f));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,88 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Binary file not shown.
|
@ -0,0 +1,7 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<packageSources>
|
||||||
|
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" />
|
||||||
|
<add key="AAron Thunderstore" value="https://nuget.windows10ce.com/nuget/v3/index.json" />
|
||||||
|
</packageSources>
|
||||||
|
</configuration>
|
12
README.md
12
README.md
|
@ -1,7 +1,6 @@
|
||||||
# Muzika Gromche!
|
# Muzika Gromche!
|
||||||
|
|
||||||
_Add some content to your Inverse teleporter experience on Titan!<sup>1</sup>_
|
Add some content to your reverse teleport experience on Titan!
|
||||||
|
|
||||||
This mod's name literally means "cranck music louder".
|
This mod's name literally means "cranck music louder".
|
||||||
To keep it a surprise, it is adviced that you do not read the detailed description below.
|
To keep it a surprise, it is adviced that you do not read the detailed description below.
|
||||||
|
|
||||||
|
@ -9,7 +8,7 @@ To keep it a surprise, it is adviced that you do not read the detailed descripti
|
||||||
|
|
||||||
Muzika Gromche is compatible with *Almost Vanilla™* gameplay and [*High Quota Mindset*](https://youtu.be/18RUCgQldGg?t=2553). It slightly changes certain timers, so won't be compatible with leaderboards. If you are a streamer™, be aware that it does play *copyrighted content.*
|
Muzika Gromche is compatible with *Almost Vanilla™* gameplay and [*High Quota Mindset*](https://youtu.be/18RUCgQldGg?t=2553). It slightly changes certain timers, so won't be compatible with leaderboards. If you are a streamer™, be aware that it does play *copyrighted content.*
|
||||||
|
|
||||||
Muzika Gromche works with all Lethal Company versions from v72 all the way back to v40, and is likely to work on all future versions as long as dependencies ([`LethalConfig`] and [`LobbyCompatibility`]) are working.
|
Muzika Gromche works with all Lethal Company versions from v72 all the way back to v40, and is likely to work on all future versions as long as dependencies ([`CSync`] and [`LethalConfig`]) are working.
|
||||||
|
|
||||||
Speaking of dependencies, [`V70PoweredLights_Fix`] is not strictly required, but it doesn't hurt to have it installed on any version, and it makes this mod more enjoyable on new Mansion tiles.
|
Speaking of dependencies, [`V70PoweredLights_Fix`] is not strictly required, but it doesn't hurt to have it installed on any version, and it makes this mod more enjoyable on new Mansion tiles.
|
||||||
|
|
||||||
|
@ -17,11 +16,10 @@ 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.
|
||||||
|
- If you experience severe lags, try disabling color animations in config.
|
||||||
- If you are playing with a Bluetooth headset, adjust Audio Offset to -0.2 seconds.
|
- If you are playing with a Bluetooth headset, adjust Audio Offset to -0.2 seconds.
|
||||||
- Display Lyrics toggle: show lyrics in a popup whenever player hears music.
|
- Display Lyrics toggle: show lyrics in a popup whenever player hears music.
|
||||||
|
|
||||||
|
@ -32,11 +30,7 @@ Any player can change their personal preferences locally.
|
||||||
- [Just Nothing](https://t.me/REALJUSTNOTHING): Visual artist; contributed palettes, timings and animation curves.
|
- [Just Nothing](https://t.me/REALJUSTNOTHING): Visual artist; contributed palettes, timings and animation curves.
|
||||||
- [WaterGun](https://www.youtube.com/channel/UCCxCFfmrnqkFZ8i9FsXBJVA): Created [`V70PoweredLights_Fix`] mod, patched certain tiles with amazing lightshow.
|
- [WaterGun](https://www.youtube.com/channel/UCCxCFfmrnqkFZ8i9FsXBJVA): Created [`V70PoweredLights_Fix`] mod, patched certain tiles with amazing lightshow.
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
1. Actually not limited to Inverse teleporter or Titan.
|
|
||||||
|
|
||||||
[`CSync`]: https://thunderstore.io/c/lethal-company/p/Sigurd/CSync/
|
[`CSync`]: https://thunderstore.io/c/lethal-company/p/Sigurd/CSync/
|
||||||
[`LethalConfig`]: https://thunderstore.io/c/lethal-company/p/AinaVT/LethalConfig/
|
[`LethalConfig`]: https://thunderstore.io/c/lethal-company/p/AinaVT/LethalConfig/
|
||||||
[`LobbyCompatibility`]: https://thunderstore.io/c/lethal-company/p/BMX/LobbyCompatibility/
|
|
||||||
[`V70PoweredLights_Fix`]: https://thunderstore.io/c/lethal-company/p/WaterGun/V70PoweredLights_Fix/
|
[`V70PoweredLights_Fix`]: https://thunderstore.io/c/lethal-company/p/WaterGun/V70PoweredLights_Fix/
|
||||||
|
|
|
@ -1,12 +0,0 @@
|
||||||
{
|
|
||||||
"version": 1,
|
|
||||||
"isRoot": true,
|
|
||||||
"tools": {
|
|
||||||
"evaisa.netcodepatcher.cli": {
|
|
||||||
"version": "4.3.0",
|
|
||||||
"commands": [
|
|
||||||
"netcode-patch"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"name": "MuzikaGromche",
|
"name": "MuzikaGromche",
|
||||||
"version_number": "1337.420.9001",
|
"version_number": "13.37.911",
|
||||||
"author": "Ratijas",
|
"author": "Oflor",
|
||||||
"description": "Add some content to your inverse teleporter experience on Titan!",
|
"description": "Glaza zakryvaj",
|
||||||
"website_url": "https://git.vilunov.me/ratijas/muzika-gromche",
|
"website_url": "https://git.vilunov.me/nikita/muzika-gromche",
|
||||||
"dependencies": [
|
"dependencies": [
|
||||||
"BepInEx-BepInExPack-5.4.2100",
|
"BepInEx-BepInExPack-5.4.2100",
|
||||||
|
"Sigurd-CSync-5.0.1",
|
||||||
"AinaVT-LethalConfig-1.4.6",
|
"AinaVT-LethalConfig-1.4.6",
|
||||||
"WaterGun-V70PoweredLights_Fix-1.0.0",
|
"WaterGun-V70PoweredLights_Fix-1.0.0"
|
||||||
"BMX-LobbyCompatibility-1.5.1"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue