Updated for v81

This commit is contained in:
Lady Alice 2026-05-01 00:06:39 -07:00
parent f0ef413d2f
commit d89b6bcec5
24 changed files with 214 additions and 90 deletions

View file

@ -1,18 +1,19 @@
using System;
using DunGen.Graph;
using DunGenPlus;
using LethalLevelLoader;
using LethalLib.Modules;
using ScarletMansion.Configs;
using ScarletMansion.ModPatch;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;
using UnityEngine;
using System.Reflection;
using System.IO;
using DunGen.Graph;
using LethalLib.Modules;
using LethalLevelLoader;
using DunGenPlus;
using ScarletMansion.ModPatch;
using ScarletMansion.Configs;
using static UnityEngine.GraphicsBuffer;
namespace ScarletMansion {
public static class Assets {
@ -33,6 +34,8 @@ namespace ScarletMansion {
// enemy values
public class Enemy {
public bool initialized;
public GameObject enemy;
public EnemyType enemyType;
public Func<int> rarityFunc;
@ -42,14 +45,15 @@ namespace ScarletMansion {
public Enemy(GameObject enemy, TerminalNode node, TerminalKeyword keyword) {
this.enemy = enemy;
this.enemyType = enemy.GetComponentInChildren<EnemyAI>().enemyType;
this.terminalNode = node;
this.terminalKeyword = keyword;
LethalLib.Modules.Enemies.RegisterEnemy(enemyType, 0, Levels.LevelTypes.None, terminalNode, terminalKeyword);
}
public SpawnableEnemyWithRarity GetItemEntry(int rarity){
var entry = new SpawnableEnemyWithRarity();
entry.enemyType = enemyType;
entry.rarity = rarity;
var entry = new SpawnableEnemyWithRarity(enemyType, rarity);
return entry;
}
}
@ -114,9 +118,8 @@ namespace ScarletMansion {
public SpawnableItemWithRarity GetItemRarity(){
var configEntry = GetConfigScrapItemEntry();
var item = new SpawnableItemWithRarity();
item.spawnableItem = this.item;
item.rarity = configEntry != null ? configEntry.spawnWeight : 0;
var rarity = configEntry != null ? configEntry.spawnWeight : 0;
var item = new SpawnableItemWithRarity(this.item, rarity);
return item;
}
@ -205,7 +208,6 @@ namespace ScarletMansion {
MainAssetBundle = AssetBundle.LoadFromStream(assetStream);
}
}
}
Plugin.ConfigFoyer.dungeon = Load<DungeonFlow>("sdmFoyer");
@ -222,7 +224,7 @@ namespace ScarletMansion {
Load<TerminalNode>("KnightNode"),
Load<TerminalKeyword>("KnightKeyword")
);
maid = new Enemy(
Load<GameObject>("NET_MaidEnemy"),
Load<TerminalNode>("MaidNode"),

View file

@ -27,10 +27,10 @@ namespace ScarletMansion.Configs
"Default",
"The default generation values. Intended for lobbies with 3+ players.",
new ChangeInt ( dunGenWidthBase, 120 ),
new ChangeInt ( dunGenLengthBase, 80 ),
new ChangeFloat ( dunGenWidthMultiFactor, 0.5f ),
new ChangeFloat ( dunGenLengthMultiFactor, 0.3333333f ),
new ChangeInt ( dunGenWidthBase, 140 ),
new ChangeInt ( dunGenLengthBase, 90 ),
new ChangeFloat ( dunGenWidthMultiFactor, 0.75f ),
new ChangeFloat ( dunGenLengthMultiFactor, 0.1428f ),
new ChangeInt ( mainPathCount, 3 ),
new ChangeMinMaxInt ( mainPathLength, 6, 7 ),

View file

@ -27,8 +27,8 @@ namespace ScarletMansion.Configs {
"Default",
"The default generation values. Intended for lobbies with 3+ players.",
new ChangeInt ( dunGenWidthBase, 120 ),
new ChangeInt ( dunGenLengthBase, 80 ),
new ChangeInt ( dunGenWidthBase, 140 ),
new ChangeInt ( dunGenLengthBase, 100 ),
new ChangeFloat ( dunGenWidthMultiFactor, 0.5f ),
new ChangeFloat ( dunGenLengthMultiFactor, 0.3333333f ),

View file

@ -133,5 +133,12 @@ namespace ScarletMansion.DunGenPatch {
return ConnectionResult.Passthrough;
}
public static void PriotizeDoorwaysGoingDownward(ref float weight, DoorwayPairCollection param, EventCallbackScenario callback){
var diff = param.nextDoor.Position.y - param.previousDoor.Position.y;
if (diff < -0.01f){
weight *= 1.25f;
}
}
}
}

View file

@ -62,11 +62,12 @@ namespace ScarletMansion.GamePatch.Components.TreasureRoom {
prop.ProcessSkipCount(randomStream, 1);
}
} else {
prop.Process(randomStream, null);
var spawned = new List<GameObject>();
prop.Process(randomStream, null, ref spawned);
}
// so the children get the process prop cycling as well
DunGenPatch.Patch.generatorInstance.ProcessProps(null, prop.transform.GetChild(0).gameObject);
Utility.ProcessLocalProps(DunGenPatch.Patch.generatorInstance, prop.transform.GetChild(0).gameObject);
}
// hack so i can set up the SpawnSycnedObject myself

View file

@ -47,6 +47,7 @@ namespace ScarletMansion.GamePatch {
[HarmonyPatch(typeof(StartOfRound), "Awake")]
[HarmonyPrefix]
public static void StartOfRound_Start(ref StartOfRound __instance) {
ScarletYukariTrigger.audioClipIndex = -1;
ScarletPlayerControllerB.InitializeScarletScripts();
DoorwayManager.onMainEntranceTeleportSpawnedEvent.ClearTemporaryActionList();
@ -118,41 +119,37 @@ namespace ScarletMansion.GamePatch {
.SelectMany(lev => lev.Enemies);
var knight = Assets.knight;
if (knight.enemyType == null){
if (!knight.initialized){
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";
if (GameReadNullCheck(springItem, "springman", "Knight enemy will not have correct assets")) {
var source = springItem.enemyType;
var target = knight.enemy.GetComponent<KnightV2Variant>().enemyType;
target.hitBodySFX = source.hitBodySFX;
knight.enemyType = type;
knight.enemy.GetComponentInChildren<EnemyAI>().enemyType = type;
LethalLib.Modules.Enemies.RegisterEnemy(type, 0, Levels.LevelTypes.None, knight.terminalNode, knight.terminalKeyword);
knight.initialized = true;
Plugin.logger.LogDebug("Initialized knight");
}
}
var maid = Assets.maid;
if (maid.enemyType == null){
if (!maid.initialized){
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;
if (GameReadNullCheck(butlerItem, "butler", "Maid enemy will not have correct assets")) {
var source = butlerItem.enemyType;
var target = maid.enemy.GetComponent<MaidVariant>().enemyType;
target.hitBodySFX = source.hitBodySFX;
target.audioClips = source.audioClips;
maid.enemyType = type;
var maidScript = maid.enemy.GetComponentInChildren<MaidVariant>();
maidScript.enemyType = type;
var butlerPrefab = butlerItem.enemyType.enemyPrefab;
var butlerScript = butlerPrefab.GetComponent<ButlerEnemyAI>();
var butlerScript = source.enemyPrefab.GetComponent<ButlerEnemyAI>();
var maidScript = target.enemyPrefab.GetComponent<MaidVariant>();
Utility.FixParticleSystemMaterialAndChildren(maidScript.stabBloodParticle, butlerScript.stabBloodParticle);
LethalLib.Modules.Enemies.RegisterEnemy(type, 0, Levels.LevelTypes.None, maid.terminalNode, maid.terminalKeyword);
maid.initialized = true;
Plugin.logger.LogDebug("Initialized maid");
}
}
@ -319,23 +316,30 @@ namespace ScarletMansion.GamePatch {
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 sourceInteract = steeldoor.Prefab.GetComponentInChildren<InteractTrigger>();
var sourceAnimate = steeldoor.Prefab.GetComponentInChildren<AnimatedObjectTrigger>();
var sourceDoor = steeldoor.Prefab.GetComponentInChildren<DoorLock>();
Assets.hoverIcon = sourceInteract.hoverIcon;
var boolFalse = animateTrigger.boolFalseAudios;
var boolTrue = animateTrigger.boolTrueAudios;
var secondary = animateTrigger.secondaryAudios;
var boolFalse = sourceAnimate.boolFalseAudios;
var boolTrue = sourceAnimate.boolTrueAudios;
var secondary = sourceAnimate.secondaryAudios;
var pickingSFX = sourceDoor.pickingLockSFX;
var unlockSFX = sourceDoor.unlockSFX;
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 doorlock = g.GetComponentInChildren<DoorLock>();
doorlock.pickingLockSFX = pickingSFX;
doorlock.unlockSFX = unlockSFX;
}
}

View file

@ -67,10 +67,7 @@ namespace ScarletMansion.GamePatch {
} else {
var entryRarity = Mathf.RoundToInt(target.rarity * enemyConfig.spawnWeightStealPercentage);
var prevEntry = new SpawnableEnemyWithRarity();
prevEntry.enemyType = target.enemyType;
prevEntry.rarity = target.rarity - entryRarity;
var prevEntry = new SpawnableEnemyWithRarity(target.enemyType, target.rarity - entryRarity);
var newEntry = enemy.GetItemEntry(enemyConfig.spawnWeightBase + entryRarity);
EnemyManager.AddEnemy(newEntry);

View file

@ -409,7 +409,6 @@ namespace ScarletMansion {
var gameObject = GameObject.Instantiate(enemy.enemyPrefab, position, Quaternion.Euler(0f, yRotation, 0f));
var networkScript = gameObject.GetComponentInChildren<NetworkObject>();
networkScript.SpawnWithOwnership(ownerID, true);
Plugin.logger.LogFatal(ownerID);
var enemyScript = gameObject.GetComponent<T>();
RoundManager.Instance.SpawnedEnemies.Add(enemyScript);

View file

@ -12,7 +12,7 @@ namespace ScarletMansion.GamePatch.Props {
public GameObject target;
public Bounds bounds;
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
var b = GetBounds();
var layerMask = LayerMask.GetMask(new string[3] { "Room", "Railing", "MapHazards" });
if (Physics.CheckBox(b.center, b.extents, transform.rotation, layerMask)){

View file

@ -15,7 +15,7 @@ namespace ScarletMansion.GamePatch.Props {
public List<GameObject> basementFloorPrefabs;
public GameObject bottomFloorPrefab;
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
var baseY = KnightSpawnManager.Instance.transform.position.y;
var currentY = tile.transform.position.y;

View file

@ -9,7 +9,7 @@ using DunGen;
namespace ScarletMansion.GamePatch.Props {
public class LocalPropSetBasic : RandomProp {
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
var transformCount = transform.childCount;
var count = Mathf.Clamp(propCount.GetRandom(randomStream), 0, transformCount);

View file

@ -9,7 +9,7 @@ using DunGen;
namespace ScarletMansion.GamePatch.Props {
public class LocalPropSingle : RandomProp {
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
if (randomizePosition){
var x = (float)randomStream.NextDouble() * randomPositionRange;

View file

@ -9,7 +9,7 @@ using DunGen;
namespace ScarletMansion.GamePatch.Props {
public class RandomPrefabBasic : RandomPrefabBase {
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
if (props.Count <= 0) return;
var value = randomStream.Next(props.Count);

View file

@ -16,7 +16,7 @@ namespace ScarletMansion.GamePatch.Props {
cycle = value;
}
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
if (props.Count <= 0) return;
Plugin.logger.LogDebug($"Cycle {cycle}");

View file

@ -1,5 +1,7 @@
using System;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using DunGen;
namespace ScarletMansion {
@ -7,7 +9,7 @@ namespace ScarletMansion {
[AddComponentMenu("DunGen/Random Props/Random Prefab with Scale")]
public class RandomPrefabWithScale : RandomProp {
public override void Process(RandomStream randomStream, Tile tile) {
public override void Process(RandomStream randomStream, Tile tile, ref List<GameObject> spawnedObjects) {
if (Props.Weights.Count <= 0) return;
var value = this.Props.GetRandom(randomStream, tile.Placement.IsOnMainPath, tile.Placement.NormalizedDepth, null, true, true).Value;

View file

@ -23,9 +23,9 @@ namespace ScarletMansion {
[BepInPlugin(modGUID, modName, modVersion)]
[BepInDependency("imabatby.lethallevelloader", "1.4.5")]
[BepInDependency("evaisa.lethallib", "0.13.2")]
[BepInDependency("dev.ladyalice.dungenplus", "1.4.0")]
[BepInDependency("imabatby.lethallevelloader", "1.6.9")]
[BepInDependency("evaisa.lethallib", "1.2.0")]
[BepInDependency("dev.ladyalice.dungenplus", "1.5.0")]
[BepInDependency("dev.ladyalice.scarletmansion.foyer")]
[BepInDependency("dev.ladyalice.scarletmansion.basement")]
//[BepInDependency(ModCompability.advancedCompanyGuid, BepInDependency.DependencyFlags.SoftDependency)]
@ -37,7 +37,7 @@ namespace ScarletMansion {
public class Plugin : BaseUnityPlugin {
public const string modGUID = "dev.ladyalice.scarletmansion";
private const string modName = "Scarlet Devil Mansion";
private const string modVersion = "2.3.0";
private const string modVersion = "2.4.0";
public readonly Harmony harmony = new Harmony(modGUID);
@ -84,7 +84,7 @@ namespace ScarletMansion {
harmony.PatchAll(typeof(ConfigPatch));
SetupForNetcodePatcher();
//SetupForNetcodePatcher();
Assets.LoadAssetBundle();
@ -127,6 +127,7 @@ namespace ScarletMansion {
extendedContent.Add(CreateExtendedDungeonFlow(ConfigFoyer, "Scarlet Foyer", 100, 200, 30));
extendedContent.Add(CreateExtendedDungeonFlow(ConfigBasement, "Scarlet Basement", 200, 100, 30));
ConfigBasement.dunGenExtender.Events.OnModifyDoorwayPairWeight.AddListener(DunGenPatch.Patch.PriotizeDoorwaysGoingDownward);
var extendedMod = ExtendedMod.Create("Scarlet Devil Mansion", "Alice", extendedContent.ToArray());

View file

@ -46,6 +46,9 @@
<Reference Include="BepInEx.Harmony">
<HintPath>..\..\..\Libraries\BepInEx.Harmony.dll</HintPath>
</Reference>
<Reference Include="DunGen-publicized">
<HintPath>..\..\..\Libraries\DunGen-publicized.dll</HintPath>
</Reference>
<Reference Include="DunGenPlus">
<HintPath>..\..\..\Libraries\DunGenPlus.dll</HintPath>
</Reference>
@ -277,10 +280,10 @@
</ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<PreBuildEvent>copy "D:\Previous Computer\Desktop\LethalCompany Modding\Unity Template\Assets\AssetBundles\scarletmansion" "$(SolutionDir)\scarletmansion"</PreBuildEvent>
<PreBuildEvent>copy "D:\Unity Projects\Lethal Company Project\Assets\AssetBundles\scarletmansion" "$(SolutionDir)\scarletmansion"</PreBuildEvent>
</PropertyGroup>
<PropertyGroup>
<PostBuildEvent>copy "$(TargetPath)" "C:\Users\Jose Garcia\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\SDM Debug\BepInEx\plugins\Alice-ScarletDevilMansion\$(TargetName).dll"
<PostBuildEvent>copy "$(TargetPath)" "C:\Users\Jose Garcia\AppData\Roaming\r2modmanPlus-local\LethalCompany\profiles\DunGenPlus\BepInEx\plugins\Alice-ScarletDevilMansion\$(TargetName).dll"
copy "$(TargetPath)" "D:\Previous Computer\Desktop\LethalCompany Modding\NetcodePatcher\plugins\$(TargetName).dll"</PostBuildEvent>
</PropertyGroup>
</Project>

View file

@ -142,6 +142,59 @@ namespace ScarletMansion {
public static class Utility {
// https://stackoverflow.com/questions/930433/apply-properties-values-from-one-object-to-another-of-the-same-type-automaticall
/// <summary>
/// Extension for 'Object' that copies the properties to a destination object.
/// </summary>
/// <param name="source">The source.</param>
/// <param name="destination">The destination.</param>
public static void CopyProperties(this object source, object destination, params string[] variableDenies)
{
// If any this null throw an exception
if (source == null || destination == null)
throw new Exception("Source or/and Destination Objects are null");
// Getting the Types of the objects
Type typeDest = destination.GetType();
Type typeSrc = source.GetType();
// Iterate the Properties of the source instance and
// populate them from their desination counterparts
PropertyInfo[] srcProps = typeSrc.GetProperties();
foreach (PropertyInfo srcProp in srcProps)
{
if (!srcProp.CanRead)
{
continue;
}
PropertyInfo targetProperty = typeDest.GetProperty(srcProp.Name);
if (targetProperty == null)
{
continue;
}
if (!targetProperty.CanWrite)
{
continue;
}
if (variableDenies.Contains(targetProperty.Name)){
continue;
}
if (targetProperty.GetSetMethod(true) != null && targetProperty.GetSetMethod(true).IsPrivate)
{
continue;
}
if ((targetProperty.GetSetMethod().Attributes & MethodAttributes.Static) != 0)
{
continue;
}
if (!targetProperty.PropertyType.IsAssignableFrom(srcProp.PropertyType))
{
continue;
}
// Passed all tests, lets set the value
targetProperty.SetValue(destination, srcProp.GetValue(source, null), null);
}
}
public static float GetRandomNumber(this System.Random random, double minimum, double maximum) {
return (float)(random.NextDouble() * (maximum - minimum) + minimum);
}
@ -381,6 +434,51 @@ namespace ScarletMansion {
}
}
public static void ProcessLocalProps(DungeonGenerator dungeonGenerator, GameObject target){
void g__GetHierarchyDepth(Transform transform, ref int depth) {
if (transform.parent != null) {
depth++;
g__GetHierarchyDepth(transform.parent, ref depth);
}
}
RandomProp[] componentsInChildren = target.GetComponentsInChildren<RandomProp>();
List<DungeonGenerator.PropProcessingData> list = new List<DungeonGenerator.PropProcessingData>();
foreach (RandomProp randomProp in componentsInChildren)
{
int hierarchyDepth = 0;
g__GetHierarchyDepth(randomProp.transform, ref hierarchyDepth);
list.Add(new DungeonGenerator.PropProcessingData
{
PropComponent = randomProp,
HierarchyDepth = hierarchyDepth,
OwningTile = randomProp.GetComponentInParent<Tile>()
});
}
list = (from x in list
orderby x.HierarchyDepth
select x).ToList<DungeonGenerator.PropProcessingData>();
List<GameObject> list2 = new List<GameObject>();
for (int j = 0; j < list.Count; j++)
{
DungeonGenerator.PropProcessingData propProcessingData = list[j];
if (!(propProcessingData.PropComponent == null))
{
list2.Clear();
propProcessingData.PropComponent.Process(dungeonGenerator.RandomStream, propProcessingData.OwningTile, ref list2);
foreach (RandomProp propComponent in list2.SelectMany((GameObject x) => x.GetComponentsInChildren<RandomProp>()).Distinct<RandomProp>())
{
list.Insert(j + 1, new DungeonGenerator.PropProcessingData
{
PropComponent = propComponent,
HierarchyDepth = propProcessingData.HierarchyDepth + 1,
OwningTile = propProcessingData.OwningTile
});
}
}
}
}
/*
public static GameObject GetParentWithNetworkObject(GameObject g){