Added disable mayor basement config

Dungeon generation now uses a universal archetype for normal Nodes (fixes mayor and hallway entrance)
This commit is contained in:
LadyAliceMargatroid 2024-05-01 22:03:11 -07:00
parent 6613191d7e
commit 882c4a0c3e
11 changed files with 158 additions and 17 deletions

View File

@ -47,7 +47,7 @@ namespace ScarletMansion {
var strList = new List<string>(); var strList = new List<string>();
values.Sort(); values.Sort();
var sectionCount = Mathf.Min(10, values.Count); var sectionCount = Mathf.Clamp(values.Count, 1, 10);
var sectionDistance = values.Count / sectionCount; var sectionDistance = values.Count / sectionCount;
for(var i = 0; i * sectionDistance < values.Count; ++i){ for(var i = 0; i * sectionDistance < values.Count; ++i){
var avg = GetAverage(values.Skip(i * sectionDistance).Take(sectionDistance)); var avg = GetAverage(values.Skip(i * sectionDistance).Take(sectionDistance));

View File

@ -11,12 +11,13 @@ namespace ScarletMansion {
public List<Doorway> groupA; public List<Doorway> groupA;
public List<Doorway> groupB; public List<Doorway> groupB;
public List<Doorway> groupC;
public List<Doorway> groupBasement;
public List<Doorway> GrabDoorwayGroup(Doorway target){ public List<Doorway> GrabDoorwayGroup(Doorway target){
if (groupA.Contains(target)) return groupA; if (groupA.Contains(target)) return groupA;
else if (groupB.Contains(target)) return groupB; else if (groupB.Contains(target)) return groupB;
else if (groupC.Contains(target)) return groupC; else if (groupBasement.Contains(target)) return groupBasement;
return null; return null;
} }

View File

@ -92,7 +92,11 @@ namespace ScarletMansion.DunGenPatch {
public static IEnumerator GenerateAlternativeMainPaths(DungeonGenerator gen) { public static IEnumerator GenerateAlternativeMainPaths(DungeonGenerator gen) {
// the amount of extra alt. paths // the amount of extra alt. paths
var altCount = PluginConfig.Instance.mainPathCountValue - 1; var altV = PluginConfig.Instance.mainPathCountValue;
if (PluginConfig.Instance.disableBasementValue) {
altV = Mathf.Min(altV, 2);
}
var altCount = altV - 1;
if (!active || altCount == 0){ if (!active || altCount == 0){
Patch.callAlternative = false; Patch.callAlternative = false;
@ -101,10 +105,10 @@ namespace ScarletMansion.DunGenPatch {
yield break; yield break;
} }
gen.ChangeStatus(GenerationStatus.Branching); gen.ChangeStatus(GenerationStatus.MainPath);
var allMainPathTiles = new List<List<TileProxy>>(); var allMainPathTiles = new List<List<TileProxy>>();
allMainPathTiles.Add(gen.proxyDungeon.MainPathTiles); allMainPathTiles.Add(gen.proxyDungeon.MainPathTiles.ToList());
// main tile is the true main room and not the fake room // main tile is the true main room and not the fake room
// this MUST have multiple doorways as you can imainge // this MUST have multiple doorways as you can imainge
@ -152,6 +156,7 @@ namespace ScarletMansion.DunGenPatch {
// and yet it worked // and yet it worked
// this is how my last node cannot be a target of pruning // this is how my last node cannot be a target of pruning
GraphNode graphNode = null; GraphNode graphNode = null;
DungeonArchetype archetype = null;
foreach(var g in nodes) { foreach(var g in nodes) {
if (lineDepthRatio >= g.Position && !nodesVisited.Contains(g)) { if (lineDepthRatio >= g.Position && !nodesVisited.Contains(g)) {
graphNode = g; graphNode = g;
@ -162,9 +167,11 @@ namespace ScarletMansion.DunGenPatch {
List<TileSet> useableTileSets; List<TileSet> useableTileSets;
if (graphNode != null) { if (graphNode != null) {
archetype = graphNode.NodeType == NodeType.Normal ? Assets.networkObjectList.hallwayEntranceArchetype : null;
useableTileSets = graphNode.TileSets; useableTileSets = graphNode.TileSets;
} else { } else {
useableTileSets = gen.currentArchetype.TileSets; archetype = gen.currentArchetype;
useableTileSets = archetype.TileSets;
} }
if (t == 1){ if (t == 1){
@ -193,7 +200,7 @@ namespace ScarletMansion.DunGenPatch {
} }
var tileProxy = gen.AddTile(previousTile, useableTileSets, lineDepthRatio, gen.currentArchetype, TilePlacementResult.None); var tileProxy = gen.AddTile(previousTile, useableTileSets, lineDepthRatio, archetype, TilePlacementResult.None);
if (tileProxy == null) { if (tileProxy == null) {
if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Alt. main branch gen failed at {b}:{lineDepthRatio}"); if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Alt. main branch gen failed at {b}:{lineDepthRatio}");
@ -210,8 +217,15 @@ namespace ScarletMansion.DunGenPatch {
tileProxy.Placement.BranchDepth = t; tileProxy.Placement.BranchDepth = t;
tileProxy.Placement.NormalizedBranchDepth = lineDepthRatio; tileProxy.Placement.NormalizedBranchDepth = lineDepthRatio;
tileProxy.Placement.GraphNode = previousTile.Placement.GraphNode;
tileProxy.Placement.GraphLine = previousTile.Placement.GraphLine; if (graphNode != null) {
tileProxy.Placement.GraphNode = graphNode;
tileProxy.Placement.GraphLine = null;
} else {
tileProxy.Placement.GraphNode = null;
tileProxy.Placement.GraphLine = lineAtDepth;
}
previousTile = tileProxy; previousTile = tileProxy;
newMainPathTiles.Add(tileProxy); newMainPathTiles.Add(tileProxy);
@ -234,11 +248,20 @@ namespace ScarletMansion.DunGenPatch {
Patch.callAlternative = false; Patch.callAlternative = false;
if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Created {altCount} alt. paths, creating branches now"); if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Created {altCount} alt. paths, creating branches now");
gen.ChangeStatus(GenerationStatus.Branching);
// this is major trickery and it works still // this is major trickery and it works still
for(var b = 0; b < altCount + 1; ++b){ for(var b = 0; b < altCount + 1; ++b){
if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Branch {b}"); if (!Patch.startAnalysis) Plugin.logger.LogInfo($"Branch {b}");
RandomizeLineArchetypes(gen, false); RandomizeLineArchetypes(gen, false);
gen.proxyDungeon.MainPathTiles = allMainPathTiles[b]; gen.proxyDungeon.MainPathTiles = allMainPathTiles[b];
/*
foreach (var t in gen.proxyDungeon.MainPathTiles){
Plugin.logger.LogInfo(t.Prefab.name);
Plugin.logger.LogInfo(t.Placement.Archetype);
}
*/
yield return gen.Wait(gen.GenerateBranchPaths()); yield return gen.Wait(gen.GenerateBranchPaths());
} }
@ -249,6 +272,12 @@ namespace ScarletMansion.DunGenPatch {
if (AnalysisUpdate(gen)) yield return gen.Wait(gen.InnerGenerate(true)); if (AnalysisUpdate(gen)) yield return gen.Wait(gen.InnerGenerate(true));
} }
public static DungeonArchetype ModifyMainBranchNodeArchetype(DungeonArchetype archetype, GraphNode node){
if (!Patch.active) return archetype;
if (node.NodeType == NodeType.Normal) return Assets.networkObjectList.hallwayEntranceArchetype;
return archetype;
}
public static bool AnalysisUpdate(DungeonGenerator gen){ public static bool AnalysisUpdate(DungeonGenerator gen){
if (Patch.startAnalysis && analTestCount <= analTestCountMax) { if (Patch.startAnalysis && analTestCount <= analTestCountMax) {
var t = Patch.stopwatch.ElapsedMilliseconds; var t = Patch.stopwatch.ElapsedMilliseconds;
@ -271,7 +300,7 @@ namespace ScarletMansion.DunGenPatch {
} }
} }
Plugin.logger.LogInfo($"C{analTestCount}, S{analAltFailCount}, R{gen.retryCount - analAltFailCount - analTestCount}\nLoot {Patch.scrapDistance.ToString()}\nFloor {Patch.scrapFloors.ToString()}"); Plugin.logger.LogInfo($"C{analTestCount}, S{analAltFailCount}, R{gen.retryCount - analAltFailCount - analTestCount}\nLoot {Patch.scrapDistance.ToString()}");
analTestCount++; analTestCount++;
Patch.stopwatch.Restart(); Patch.stopwatch.Restart();

View File

@ -54,5 +54,70 @@ namespace ScarletMansion.DunGenPatch {
Plugin.logger.LogInfo("Alt. InnerGenerate() function complete"); Plugin.logger.LogInfo("Alt. InnerGenerate() function complete");
} }
} }
[HarmonyTranspiler]
[HarmonyPatch(typeof(DungeonGenerator), "GenerateMainPath", MethodType.Enumerator)]
public static IEnumerable<CodeInstruction> GenerateMainPathPatch(IEnumerable<CodeInstruction> instructions){
var addFunction = typeof(List<DungeonArchetype>).GetMethod("Add", BindingFlags.Instance | BindingFlags.Public);
var sequence = new InstructionSequence("archetype node");
sequence.AddOperandTypeCheck(OpCodes.Ldfld, typeof(List<DungeonArchetype>));
sequence.AddBasic(OpCodes.Ldnull);
sequence.AddBasic(OpCodes.Callvirt, addFunction);
foreach(var instruction in instructions){
if (sequence.VerifyStage(instruction)){
var method = typeof(GeneratePath).GetMethod("ModifyMainBranchNodeArchetype", BindingFlags.Public | BindingFlags.Static);
yield return new CodeInstruction(OpCodes.Ldloc_S, 8);
yield return new CodeInstruction(OpCodes.Call, method);
yield return instruction;
continue;
} }
yield return instruction;
}
sequence.ReportComplete();
}
/*
[HarmonyPatch(typeof(DungeonGenerator), "AddTile")]
[HarmonyPostfix]
public static void AddTilePatch(TileProxy attachTo, IEnumerable<TileSet> useableTileSets, DungeonArchetype archetype, ref TileProxy __result){
var atString = attachTo != null ? attachTo.Prefab.ToString() : "NULL";
var aString = archetype ? archetype.ToString() : "NULL";
var rString = __result != null ? __result.Prefab.ToString() : "NULL";
Plugin.logger.LogInfo($"");
Plugin.logger.LogInfo($"Attach: {atString}");
Plugin.logger.LogInfo($"ValidCount: {useableTileSets.Sum(u => u.TileWeights.Weights.Count).ToString()}");
Plugin.logger.LogInfo($"Entry: {aString}");
Plugin.logger.LogInfo($"Result: {rString}");
}
[HarmonyPatch(typeof(DungeonGenerator), "TryPlaceTile")]
[HarmonyPostfix]
public static void TryPlaceTilePatch(ref TilePlacementResult __result){
Plugin.logger.LogInfo(__result.ToString());
}
[HarmonyPatch(typeof(DoorwayPairFinder), "GetDoorwayPairs")]
[HarmonyPostfix]
public static void GetDoorwayPairsPatch(ref Queue<DoorwayPair> __result){
Plugin.logger.LogInfo(__result.Count().ToString());
}
*/
}
} }

View File

@ -67,7 +67,6 @@ namespace ScarletMansion.DunGenPatch {
Plugin.logger.LogError(e.ToString()); Plugin.logger.LogError(e.ToString());
} }
if (startAnalysis) ActivateAnalysis(); if (startAnalysis) ActivateAnalysis();
} }

View File

@ -13,6 +13,7 @@ using Unity.Netcode;
using LethalLevelLoader; using LethalLevelLoader;
using static UnityEngine.GraphicsBuffer; using static UnityEngine.GraphicsBuffer;
using ScarletMansion.GamePatch.Components; using ScarletMansion.GamePatch.Components;
using System.Security.Cryptography;
namespace ScarletMansion.GamePatch { namespace ScarletMansion.GamePatch {
@ -370,6 +371,9 @@ namespace ScarletMansion.GamePatch {
//Assets.dungeonExtended.DynamicDungeonSizeMinMax = new Vector2(PluginConfig.Instance.dunGenMultiplierValue.min, PluginConfig.Instance.dunGenMultiplierValue.max); //Assets.dungeonExtended.DynamicDungeonSizeMinMax = new Vector2(PluginConfig.Instance.dunGenMultiplierValue.min, PluginConfig.Instance.dunGenMultiplierValue.max);
Assets.dungeon.Length = PluginConfig.Instance.mainPathLengthValue.GetDungenIntRange(); Assets.dungeon.Length = PluginConfig.Instance.mainPathLengthValue.GetDungenIntRange();
var mayorTileSet = PluginConfig.Instance.disableBasementValue ? Assets.networkObjectList.mayorVanillaTileset : Assets.networkObjectList.mayorRegularTileset;
Assets.dungeon.Nodes[1].TileSets = new List<DunGen.TileSet>() { mayorTileSet };
DungeonFlow.GlobalPropSettings GetGlobalPropSetting(int id) { DungeonFlow.GlobalPropSettings GetGlobalPropSetting(int id) {
foreach(var p in Assets.dungeon.GlobalProps){ foreach(var p in Assets.dungeon.GlobalProps){
if (p.ID == id ) return p; if (p.ID == id ) return p;

View File

@ -23,10 +23,13 @@ namespace ScarletMansion {
public List<Item> items; public List<Item> items;
[Header("DunGen")] [Header("DunGen")]
public TileSet mayorRegularTileset;
public TileSet mayorVanillaTileset;
public DungeonArchetype hallwayEntranceArchetype;
public List<DungeonArchetype> archetypes; public List<DungeonArchetype> archetypes;
public List<TileSet> tilesets; public List<TileSet> tilesets;
//public GameObject mainMenuPrefab;
[Header("Main Prefabs")] [Header("Main Prefabs")]
public GameObject scarletNetworkManager; public GameObject scarletNetworkManager;
public AudioClip sinkingAudioClip; public AudioClip sinkingAudioClip;

View File

@ -33,7 +33,7 @@ namespace ScarletMansion {
public class Plugin : BaseUnityPlugin { public class Plugin : BaseUnityPlugin {
public const string modGUID = "ImoutoSama.ScarletMansion"; public const string modGUID = "ImoutoSama.ScarletMansion";
private const string modName = "Scarlet Mansion"; private const string modName = "Scarlet Mansion";
private const string modVersion = "1.3.12"; private const string modVersion = "1.3.13";
public readonly Harmony harmony = new Harmony(modGUID); public readonly Harmony harmony = new Harmony(modGUID);

View File

@ -168,11 +168,20 @@ namespace ScarletMansion {
$"The minimum allowed length of the main path. This value is multiplied by the dungeon's size.\n\n{_mainPathLengthPostMessage}", $"The minimum allowed length of the main path. This value is multiplied by the dungeon's size.\n\n{_mainPathLengthPostMessage}",
$"The maximum allowed length of the main path. This value is multiplied by the dungeon's size.\n\n{_mainPathLengthPostMessage}", $"The maximum allowed length of the main path. This value is multiplied by the dungeon's size.\n\n{_mainPathLengthPostMessage}",
null, null,
new AcceptableValueRange<int>(2, 20) new AcceptableValueRange<int>(3, 20)
);
public static ConfigEntryBundle<bool> disableBasement = new ConfigEntryBundle<bool>(
dungeonGenerationMPathsPrefix,
"Disable Mayor Basement",
false,
"Removes the basement section of the mayor tile. Forces the Main Path Count to a maximum of 2."
); );
public int mainPathCountValue; public int mainPathCountValue;
public IntRange mainPathLengthValue = new IntRange("main path length"); public IntRange mainPathLengthValue = new IntRange("main path length");
public bool disableBasementValue;
// branching path // branching path
private static string _branchPathBranchCountMessage(int section, string minmax, string middleSection) => $"The {minmax} amount of branching paths in Section {section} of the dungeon generation process.\n{middleSection}\n\n{_branchPathPostCountMessage}"; private static string _branchPathBranchCountMessage(int section, string minmax, string middleSection) => $"The {minmax} amount of branching paths in Section {section} of the dungeon generation process.\n{middleSection}\n\n{_branchPathPostCountMessage}";
@ -187,11 +196,11 @@ namespace ScarletMansion {
private static readonly string _branchPathPostDepthMessage = $"Each branching path will try to generate a number of connecting tiles equal to this number. {_branchPathPostGenericMessage}"; private static readonly string _branchPathPostDepthMessage = $"Each branching path will try to generate a number of connecting tiles equal to this number. {_branchPathPostGenericMessage}";
public static ConfigEntryBundleBranchingPath branchPathSectionOne = new ConfigEntryBundleBranchingPath( public static ConfigEntryBundleBranchingPath branchPathSectionOne = new ConfigEntryBundleBranchingPath(
dungeonGenerationBPathOnePrefix, 1, _branchPathSectionOneMessage, 6, 8, 0, 2 dungeonGenerationBPathOnePrefix, 1, _branchPathSectionOneMessage, 4, 6, 1, 2
); );
public static ConfigEntryBundleBranchingPath branchPathSectionTwo = new ConfigEntryBundleBranchingPath( public static ConfigEntryBundleBranchingPath branchPathSectionTwo = new ConfigEntryBundleBranchingPath(
dungeonGenerationBPathTwoPrefix, 2, _branchPathSectionTwoMessage, 2, 3, 0, 1 dungeonGenerationBPathTwoPrefix, 2, _branchPathSectionTwoMessage, 2, 3, 1, 2
); );
public static ConfigEntryBundleBranchingPath branchPathSectionThree = new ConfigEntryBundleBranchingPath( public static ConfigEntryBundleBranchingPath branchPathSectionThree = new ConfigEntryBundleBranchingPath(

View File

@ -32,6 +32,7 @@ namespace ScarletMansion {
new ChangeInt ( PluginConfig.mainPathCount ), new ChangeInt ( PluginConfig.mainPathCount ),
new ChangeMinMaxInt ( PluginConfig.mainPathLength ), new ChangeMinMaxInt ( PluginConfig.mainPathLength ),
new ChangeBool( PluginConfig.disableBasement ),
new ChangeBranchingPath( PluginConfig.branchPathSectionOne ), new ChangeBranchingPath( PluginConfig.branchPathSectionOne ),
new ChangeBranchingPath( PluginConfig.branchPathSectionTwo ), new ChangeBranchingPath( PluginConfig.branchPathSectionTwo ),
@ -76,6 +77,7 @@ namespace ScarletMansion {
); );
public static ChangeList bitMoreLootGeneration = new ChangeList( public static ChangeList bitMoreLootGeneration = new ChangeList(
"Bit More Loot, Bit More Danger", "Bit More Loot, Bit More Danger",
"Increases the amount of loot, map hazards, and starting enemies in the mansion a bit. Intended for lobbies with 1-3 players.", "Increases the amount of loot, map hazards, and starting enemies in the mansion a bit. Intended for lobbies with 1-3 players.",
@ -103,6 +105,11 @@ namespace ScarletMansion {
new ChangeInt ( PluginConfig.mainPathCount, 1 ), new ChangeInt ( PluginConfig.mainPathCount, 1 ),
new ChangeMinMaxInt ( PluginConfig.mainPathLength, 6, 9 ), new ChangeMinMaxInt ( PluginConfig.mainPathLength, 6, 9 ),
new ChangeBool( PluginConfig.disableBasement, true ),
new ChangeBranchingPath( PluginConfig.branchPathSectionOne, 4, 6, 3, 4 ),
new ChangeBranchingPath( PluginConfig.branchPathSectionTwo, 2, 3, 2, 3 ),
new ChangeBranchingPath( PluginConfig.branchPathSectionThree, 1, 2, 1, 2 ),
new ChangeFloat ( PluginConfig.lootMultiplier, 1f ), new ChangeFloat ( PluginConfig.lootMultiplier, 1f ),
@ -270,6 +277,11 @@ namespace ScarletMansion {
} }
} }
public class ChangeBool : ChangeType<bool> {
public ChangeBool(PluginConfig.ConfigEntryBundle<bool> configEntry) : base (configEntry){ }
public ChangeBool(PluginConfig.ConfigEntryBundle<bool> configEntry, bool value) : base (configEntry, value){ }
}
public class ChangeFloat : ChangeType<float> { public class ChangeFloat : ChangeType<float> {
public ChangeFloat(PluginConfig.ConfigEntryBundle<float> configEntry) : base (configEntry){ } public ChangeFloat(PluginConfig.ConfigEntryBundle<float> configEntry) : base (configEntry){ }
public ChangeFloat(PluginConfig.ConfigEntryBundle<float> configEntry, float value) : base (configEntry, value){ } public ChangeFloat(PluginConfig.ConfigEntryBundle<float> configEntry, float value) : base (configEntry, value){ }

View File

@ -83,6 +83,17 @@ namespace ScarletMansion {
seq.Add((i) => i.opcode == opcode && i.operand == operand); seq.Add((i) => i.opcode == opcode && i.operand == operand);
} }
public void AddOperandTypeCheck(OpCode opcode, Type operandType){
seq.Add((i) => {
var fieldInfo = i.operand as FieldInfo;
if (i.opcode == opcode && fieldInfo != null) {
return fieldInfo.FieldType == operandType;
}
return false;
});
}
public void AddBasicWithAlternateMethodName(OpCode opcode, object operand, string methodName){ public void AddBasicWithAlternateMethodName(OpCode opcode, object operand, string methodName){
seq.Add((i) => { seq.Add((i) => {
if (i.opcode == opcode && i.operand == operand) return true; if (i.opcode == opcode && i.operand == operand) return true;
@ -162,5 +173,13 @@ namespace ScarletMansion {
return Mathf.Abs((float)instruction.operand - value) < 0.1f; return Mathf.Abs((float)instruction.operand - value) < 0.1f;
} }
public static void PrintInstructions(IEnumerable<CodeInstruction> instructions) {
foreach(var i in instructions){
var opString = i.opcode.ToString();
var objString = i.operand != null ? i.operand.ToString() : "NULL";
Plugin.logger.LogInfo($"{opString}: {objString}");
}
}
} }
} }