400 lines
17 KiB
C#
400 lines
17 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using System.Threading.Tasks;
|
|
using HarmonyLib;
|
|
using UnityEngine;
|
|
using DunGen.Graph;
|
|
using ScarletMansion.DunGenPatch;
|
|
using LethalLib.Modules;
|
|
using Unity.Netcode;
|
|
using LethalLevelLoader;
|
|
using static UnityEngine.GraphicsBuffer;
|
|
using ScarletMansion.GamePatch.Components;
|
|
using System.Security.Cryptography;
|
|
using ScarletMansion.GamePatch.Enemies;
|
|
using UnityEngine.UI;
|
|
using ScarletMansion.GamePatch.Items;
|
|
using DunGenPlus.Managers;
|
|
using ScarletMansion.Configs;
|
|
|
|
namespace ScarletMansion.GamePatch {
|
|
|
|
public class InitPatch {
|
|
|
|
private static void CreateNetworkManager(StartOfRound __instance){
|
|
Plugin.logger.LogDebug($"IsServer: {__instance.IsServer}");
|
|
if (__instance.IsServer) {
|
|
if (ScarletNetworkManager.Instance == null) {
|
|
var prefab = Assets.networkObjectList.scarletNetworkManager;
|
|
var obj = GameObject.Instantiate(prefab);
|
|
var comp = obj.GetComponent<NetworkObject>();
|
|
comp.Spawn(false);
|
|
Plugin.logger.LogDebug("Created Scarlet Network Manager. We in");
|
|
} else {
|
|
Plugin.logger.LogWarning("Scarlet Network Manager already exists? Probably scary");
|
|
}
|
|
}
|
|
}
|
|
|
|
private static IEnumerator WaitForNetworkObject(StartOfRound __instance, Action<StartOfRound> action){
|
|
while(__instance.NetworkObject.IsSpawned == false) {
|
|
yield return null;
|
|
}
|
|
action(__instance);
|
|
}
|
|
|
|
[HarmonyPatch(typeof(StartOfRound), "Awake")]
|
|
[HarmonyPrefix]
|
|
public static void StartOfRound_Start(ref StartOfRound __instance) {
|
|
ScarletYukariTrigger.audioClipIndex = -1;
|
|
ScarletPlayerControllerB.InitializeScarletScripts();
|
|
DoorwayManager.onMainEntranceTeleportSpawnedEvent.ClearTemporaryActionList();
|
|
|
|
__instance.StartCoroutine(WaitForNetworkObject(__instance, CreateNetworkManager));
|
|
|
|
// safety cleaning
|
|
DunGenPatch.Patch.Deactivate(true);
|
|
//ScarletLightingManager.Clean();
|
|
|
|
FixMapReferences(__instance);
|
|
FixItemPrefabValues(__instance);
|
|
|
|
// fix audio clips
|
|
var statusEffectClips = __instance.statusEffectClips.ToList();
|
|
ScarletYukariTrigger.audioClipIndex = statusEffectClips.Count;
|
|
statusEffectClips.Add(Assets.networkObjectList.sinkingAudioClip);
|
|
__instance.statusEffectClips = statusEffectClips.ToArray();
|
|
|
|
}
|
|
|
|
[HarmonyPatch(typeof(RoundManager), "Awake")]
|
|
[HarmonyPrefix]
|
|
public static void RoundManagerAwakePatch(ref RoundManager __instance) {
|
|
FixDungeonPrefabValues(__instance);
|
|
}
|
|
|
|
[HarmonyPatch(typeof(RoundManager), "Start")]
|
|
[HarmonyPostfix]
|
|
public static void RoundManagerStartPatch(ref RoundManager __instance) {
|
|
MyOwnCoroutine.AddCoroutine(UpdateConfigMain());
|
|
MyOwnCoroutine.AddCoroutine(UpdateConfigDungeon(ConfigDungeonFoyer.Instance));
|
|
MyOwnCoroutine.AddCoroutine(UpdateConfigDungeon(ConfigDungeonBasement.Instance));
|
|
}
|
|
|
|
public static bool GameReadNullCheck(object target, string targetString, string error) {
|
|
if (target == null) {
|
|
Plugin.logger.LogError($"Error when find ({targetString}). {error}!");
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
public static void FixMapReferences(StartOfRound round){
|
|
|
|
try {
|
|
// use the names of assets instead of the itemName or enemyName
|
|
// to account for the korean patch and such
|
|
if (Assets.genericItemGroup == null || Assets.tabletopItemGroup == null){
|
|
var bottleItem = round.allItemsList.itemsList
|
|
.FirstOrDefault(i => i.name.ToLowerInvariant() == "bottlebin");
|
|
|
|
if (GameReadNullCheck(bottleItem, "bottlebin", "Generic/Tabletop scrap will not spawn")){
|
|
Assets.genericItemGroup = bottleItem.spawnPositionTypes[0];
|
|
Assets.tabletopItemGroup = bottleItem.spawnPositionTypes[1];
|
|
}
|
|
}
|
|
|
|
if (Assets.smallItemGroup == null){
|
|
var cupValue = round.allItemsList.itemsList
|
|
.FirstOrDefault(i => i.name.ToLowerInvariant() == "fancycup");
|
|
|
|
if (GameReadNullCheck(cupValue, "fancycup", "Small scrap will not spawn")){
|
|
Assets.smallItemGroup = cupValue.spawnPositionTypes[1];
|
|
}
|
|
}
|
|
|
|
var allEnemies = round.levels
|
|
.SelectMany(lev => lev.Enemies);
|
|
|
|
var knight = Assets.knight;
|
|
if (knight.enemyType == null){
|
|
var springItem = allEnemies.FirstOrDefault(e => e.enemyType.name.ToLowerInvariant() == "springman");
|
|
|
|
if (GameReadNullCheck(springItem, "springman", "Knight enemy will not spawn")) {
|
|
var type = ScriptableObject.Instantiate(springItem.enemyType);
|
|
type.name = "Knight";
|
|
type.enemyPrefab = knight.enemy;
|
|
type.enemyName = "Knight";
|
|
|
|
knight.enemyType = type;
|
|
knight.enemy.GetComponentInChildren<EnemyAI>().enemyType = type;
|
|
LethalLib.Modules.Enemies.RegisterEnemy(type, 0, Levels.LevelTypes.None, knight.terminalNode, knight.terminalKeyword);
|
|
}
|
|
}
|
|
|
|
var maid = Assets.maid;
|
|
if (maid.enemyType == null){
|
|
var butlerItem = allEnemies.FirstOrDefault(e => e.enemyType.name.ToLowerInvariant() == "butler");
|
|
|
|
if (GameReadNullCheck(butlerItem, "butler", "Maid enemy will not spawn")) {
|
|
var type = ScriptableObject.Instantiate(butlerItem.enemyType);
|
|
type.name = "Maid";
|
|
type.enemyPrefab = maid.enemy;
|
|
type.enemyName = "Maid";
|
|
type.pushPlayerForce *= 0.25f;
|
|
|
|
maid.enemyType = type;
|
|
var maidScript = maid.enemy.GetComponentInChildren<MaidVariant>();
|
|
maidScript.enemyType = type;
|
|
|
|
var butlerPrefab = butlerItem.enemyType.enemyPrefab;
|
|
var butlerScript = butlerPrefab.GetComponent<ButlerEnemyAI>();
|
|
Utility.FixParticleSystemMaterialAndChildren(maidScript.stabBloodParticle, butlerScript.stabBloodParticle);
|
|
|
|
LethalLib.Modules.Enemies.RegisterEnemy(type, 0, Levels.LevelTypes.None, maid.terminalNode, maid.terminalKeyword);
|
|
}
|
|
}
|
|
|
|
|
|
} catch (Exception e) {
|
|
Plugin.logger.LogError("Error when reading base game's item list. Pretty big error I would say");
|
|
Plugin.logger.LogError(e);
|
|
return;
|
|
}
|
|
}
|
|
|
|
public static void FixItemPrefabValues(StartOfRound round){
|
|
|
|
try {
|
|
|
|
var itemsList = round.allItemsList.itemsList;
|
|
|
|
void QuickItemFix(Item itemToFix, Item itemReference){
|
|
if (itemToFix.itemIcon == null) itemToFix.itemIcon = itemReference.itemIcon;
|
|
if (itemToFix.grabSFX == null) itemToFix.grabSFX = itemReference.grabSFX;
|
|
if (itemToFix.dropSFX == null) itemToFix.dropSFX = itemReference.dropSFX;
|
|
if (itemToFix.pocketSFX == null) itemToFix.pocketSFX = itemReference.pocketSFX;
|
|
}
|
|
|
|
var magClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "magnifyingglass");
|
|
if (GameReadNullCheck(magClass, "magnifyingglass", "Item will have missing image and sound assets")) {
|
|
QuickItemFix(Assets.scrapItems[0].item, magClass);
|
|
QuickItemFix(Assets.scrapItems[1].item, magClass);
|
|
QuickItemFix(Assets.scrapItems[4].item, magClass);
|
|
Assets.scrapItems[5].item.itemIcon = magClass.itemIcon;
|
|
}
|
|
|
|
var paintClass = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "fancypainting");
|
|
if (GameReadNullCheck(paintClass, "fancypainting", "Item will have missing image and sound assets")){
|
|
QuickItemFix(Assets.scrapItems[2].item, paintClass);
|
|
}
|
|
|
|
void UpdateFlashlight(Assets.Flashlight flashlight, string search, int fixIndex){
|
|
var flashItem = round.allItemsList.itemsList
|
|
.FirstOrDefault(i => i.name.ToLowerInvariant() == search);
|
|
|
|
if (GameReadNullCheck(flashItem, search, "CRYSTAL FLASHLIGHT WILL FAIL")){
|
|
var prefab = Assets.networkObjectList.toFixGameObjects[fixIndex];
|
|
|
|
var item = ScriptableObject.Instantiate(flashItem);
|
|
item.name = flashlight.assetName;
|
|
item.itemName = flashlight.displayName;
|
|
item.saveItemVariable = true;
|
|
item.batteryUsage *= 1.5f;
|
|
item.spawnPrefab = prefab;
|
|
item.weight += 0.02f;
|
|
item.isScrap = true;
|
|
|
|
flashlight.item = item;
|
|
flashlight.lethalVanillaItem = flashItem;
|
|
|
|
var scarletItemComp = prefab.GetComponentInChildren<FlashlightItem>();
|
|
var refItemComp = flashItem.spawnPrefab.GetComponentInChildren<FlashlightItem>();
|
|
scarletItemComp.bulbDark = refItemComp.bulbDark;
|
|
scarletItemComp.bulbLight = refItemComp.bulbLight;
|
|
scarletItemComp.flashlightClips = refItemComp.flashlightClips;
|
|
scarletItemComp.flashlightFlicker = refItemComp.flashlightFlicker;
|
|
scarletItemComp.outOfBatteriesClip = refItemComp.outOfBatteriesClip;
|
|
scarletItemComp.itemProperties = item;
|
|
|
|
var scarletAudioComp = scarletItemComp.flashlightAudio;
|
|
var refAudioComp = refItemComp.flashlightAudio;
|
|
scarletAudioComp.SetCustomCurve(AudioSourceCurveType.CustomRolloff, refAudioComp.GetCustomCurve(AudioSourceCurveType.CustomRolloff));
|
|
|
|
var scarletLightComp = scarletItemComp.flashlightBulb;
|
|
var refLightComp = refItemComp.flashlightBulb;
|
|
scarletLightComp.cookie = refLightComp.cookie;
|
|
|
|
void CopyAndPasteMeshFilterAndRenderer(MeshRenderer meshScarlet, MeshRenderer meshReference){
|
|
meshScarlet.sharedMaterials = meshReference.sharedMaterials;
|
|
var scarletMeshComp = meshScarlet.GetComponent<MeshFilter>();
|
|
var refMeshComp = meshReference.GetComponent<MeshFilter>();
|
|
scarletMeshComp.sharedMesh = refMeshComp.sharedMesh;
|
|
}
|
|
|
|
CopyAndPasteMeshFilterAndRenderer(scarletItemComp.flashlightMesh, refItemComp.flashlightMesh);
|
|
var scarletTie = scarletItemComp.flashlightMesh.transform.Find("Tie");
|
|
var refTie = refItemComp.flashlightMesh.transform.Find("Tie");
|
|
if (scarletTie && refTie) {
|
|
var scarletTieMesh = scarletTie.GetComponent<MeshRenderer>();
|
|
var refTieMesh = refTie.GetComponent<MeshRenderer>();
|
|
if (scarletTieMesh && refTieMesh) {
|
|
Plugin.logger.LogDebug("Fixed tie of bb flashlight");
|
|
CopyAndPasteMeshFilterAndRenderer(scarletTieMesh, refTieMesh);
|
|
}
|
|
}
|
|
|
|
LethalLib.Modules.Items.RegisterItem(item);
|
|
}
|
|
}
|
|
|
|
var knifeItem = round.allItemsList.itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "knife");
|
|
if (GameReadNullCheck(knifeItem, "knife", "Item will have missing image and sound assets")){
|
|
var scarletKnife = Assets.scrapItems[3].item;
|
|
QuickItemFix(scarletKnife, knifeItem);
|
|
|
|
var scarletPrefab = scarletKnife.spawnPrefab;
|
|
var scarletScript = scarletPrefab.GetComponent<ScarletKnife>();
|
|
|
|
var knifePrefab = knifeItem.spawnPrefab;
|
|
var knifeScript = knifePrefab.GetComponent<KnifeItem>();
|
|
|
|
scarletScript.hitSFX = knifeScript.hitSFX;
|
|
scarletScript.swingSFX = knifeScript.swingSFX;
|
|
|
|
Utility.FixParticleSystemMaterialAndChildren(scarletScript.bloodParticle, knifeScript.bloodParticle);
|
|
Utility.FixParticleSystemMaterial(scarletScript.buffedParticleSystem, knifeScript.bloodParticle);
|
|
}
|
|
|
|
var shovelItem = itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "shovel");
|
|
if (GameReadNullCheck(shovelItem, "shovel", "Item will have missing image and sound assets")){
|
|
QuickItemFix(Assets.scrapItems[5].item, shovelItem);
|
|
var shovelScript = shovelItem.spawnPrefab.GetComponent<Shovel>();
|
|
var goheiScript = Assets.scrapItems[5].item.spawnPrefab.GetComponent<ScarletGohei>();
|
|
|
|
goheiScript.reelUp = shovelScript.reelUp;
|
|
goheiScript.swing = shovelScript.swing;
|
|
}
|
|
|
|
if (Assets.flashlight.item == null) {
|
|
UpdateFlashlight(Assets.flashlight, "proflashlight", 2);
|
|
}
|
|
|
|
if (Assets.flashlightBB.item == null) {
|
|
UpdateFlashlight(Assets.flashlightBB, "flashlight", 3);
|
|
}
|
|
|
|
var keyItem = round.allItemsList.itemsList.FirstOrDefault(i => i.name.ToLowerInvariant() == "key");
|
|
if (GameReadNullCheck(keyItem, "key", "Item will have missing image and sound assets")){
|
|
var scarletPrefab = Assets.networkObjectList.toFixGameObjects[5];
|
|
var scarletKey = scarletPrefab.GetComponent<GrabbableObject>().itemProperties;
|
|
QuickItemFix(scarletKey, keyItem);
|
|
|
|
var keyPrefab = keyItem.spawnPrefab;
|
|
scarletPrefab.GetComponent<MeshFilter>().sharedMesh = keyPrefab.GetComponent<MeshFilter>().sharedMesh;
|
|
|
|
var mats = keyPrefab.GetComponent<MeshRenderer>().sharedMaterials;
|
|
mats = mats.Select(m => {
|
|
var n = new Material(m);
|
|
n.color = Color.red;
|
|
return n;
|
|
}).ToArray();
|
|
scarletPrefab.GetComponent<MeshRenderer>().sharedMaterials = mats;
|
|
}
|
|
|
|
} catch (Exception e) {
|
|
Plugin.logger.LogError("Error when reading base game's item list. Pretty big error I would say");
|
|
Plugin.logger.LogError(e);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
public static void FixDungeonPrefabValues(RoundManager manager){
|
|
|
|
var networkmanager = GameObject.FindObjectOfType<NetworkManager>();
|
|
var prefabs = networkmanager.NetworkConfig.Prefabs.Prefabs;
|
|
var prefabFixList = Assets.networkObjectList.toFixGameObjects;
|
|
|
|
var steeldoor = prefabs.FirstOrDefault(p => p.Prefab.name.ToLowerInvariant() == "fancydoormapmodel");
|
|
if (GameReadNullCheck(steeldoor, "FancyDoorMapModel", "SDM doors will have missing icons and sounds")){
|
|
var interact = steeldoor.Prefab.GetComponentInChildren<InteractTrigger>();
|
|
var animateTrigger = steeldoor.Prefab.GetComponentInChildren<AnimatedObjectTrigger>();
|
|
Assets.hoverIcon = interact.hoverIcon;
|
|
|
|
var boolFalse = animateTrigger.boolFalseAudios;
|
|
var boolTrue = animateTrigger.boolTrueAudios;
|
|
var secondary = animateTrigger.secondaryAudios;
|
|
|
|
FixDoorway(prefabFixList[0]);
|
|
FixDoorway(prefabFixList[1]);
|
|
|
|
void FixDoorway(GameObject g){
|
|
var animate = g.GetComponentInChildren<AnimatedObjectTrigger>();
|
|
|
|
animate.boolFalseAudios = boolFalse;
|
|
animate.boolTrueAudios = boolTrue;
|
|
animate.secondaryAudios = secondary;
|
|
}
|
|
}
|
|
|
|
var mine = prefabs.FirstOrDefault(p => p.Prefab.name.ToLowerInvariant() == "landmine");
|
|
var turret = prefabs.FirstOrDefault(p => p.Prefab.name.ToLowerInvariant() == "turretcontainer");
|
|
var spiketrap = prefabs.FirstOrDefault(p => p.Prefab.name.ToLowerInvariant() == "spikerooftraphazard");
|
|
|
|
if (GameReadNullCheck(mine, "LandMine", "Map Object Hazards will not spawn") && GameReadNullCheck(turret, "TurretContainer", "Map Object Hazards will not spawn") && GameReadNullCheck(spiketrap, "SpikeRoofTrapHazard", "Map Object Hazards will not spawn")){
|
|
Assets.dungeonMapHazardFound = true;
|
|
Assets.dungeonMinesMapHazard = mine.Prefab;
|
|
Assets.dungeonTurretMapHazard = turret.Prefab;
|
|
Assets.dungeonSpikeTrapMapHazard = spiketrap.Prefab;
|
|
|
|
}
|
|
|
|
try {
|
|
var flow = manager.dungeonFlowTypes.Select(d => d.dungeonFlow).FirstOrDefault(d => d.name == "Level1Flow");
|
|
var tiles = flow.Nodes[1].TileSets[0].TileWeights.Weights;
|
|
var doorways = tiles.SelectMany(t => t.Value.GetComponentsInChildren<DunGen.Doorway>());
|
|
var blockers = doorways.SelectMany(d => d.BlockerPrefabWeights).Select(e => e.GameObject);
|
|
var globalprops = blockers.SelectMany(b => b.GetComponentsInChildren<DunGen.GlobalProp>());
|
|
var fireProp = globalprops.FirstOrDefault(f => f.PropGroupID == 1231);
|
|
prefabFixList[4].GetComponent<FixValues.FixFireExit>().Setup(fireProp.gameObject);
|
|
|
|
} catch (Exception e){
|
|
Plugin.logger.LogDebug("Failed to setup vanilla fire exit. The 'Use SDM Fire Exits' config will be ignored");
|
|
Plugin.logger.LogError(e.ToString());
|
|
}
|
|
|
|
|
|
}
|
|
|
|
private static IEnumerator UpdateConfigMain(){
|
|
while(ConfigMain.Synced == false){
|
|
yield return null;
|
|
}
|
|
|
|
foreach(var scrap in Assets.scrapItems){
|
|
scrap.UpdateItemValue();
|
|
}
|
|
|
|
Plugin.logger.LogDebug("Config Main updated");
|
|
}
|
|
|
|
private static IEnumerator UpdateConfigDungeon<T>(ConfigDungeon<T> instance) where T: ConfigDungeon<T>{
|
|
while(instance.SyncedLocal == false){
|
|
yield return null;
|
|
}
|
|
|
|
var defaultKeyPrefab = typeof(DungeonLoader).GetField("defaultKeyPrefab", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Static).GetValue(null) as GameObject;
|
|
|
|
instance.dungeon.Length = instance.mainPathLengthValue.GetDungenIntRange();
|
|
instance.dungeonExtended.OverrideKeyPrefab = Assets.key.GetConfigItemEntry().enabled ? Assets.key.item.spawnPrefab : defaultKeyPrefab;
|
|
|
|
Plugin.logger.LogDebug($"Config {typeof(T)} updated");
|
|
}
|
|
|
|
}
|
|
}
|