Critical damage renamed to marked for death and all share the same mechanic now Revelant now slows down to speed over a fixed short amount instead the nonworking jank before Moved item/enemy injection to DunGenPlus
		
			
				
	
	
		
			455 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			455 lines
		
	
	
	
		
			18 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
| using System;
 | |
| using System.Collections.Generic;
 | |
| using System.Linq;
 | |
| using System.Text;
 | |
| using System.Threading.Tasks;
 | |
| using Unity.Netcode;
 | |
| using System.Runtime.Serialization.Formatters.Binary;
 | |
| using System.IO;
 | |
| using HarmonyLib;
 | |
| using BepInEx;
 | |
| using BepInEx.Configuration;
 | |
| using BepInEx.Logging;
 | |
| using UnityEngine;
 | |
| using System.Reflection;
 | |
| using static ScarletMansion.PluginConfig;
 | |
| 
 | |
| namespace ScarletMansion {
 | |
|   public partial class PluginConfig : SyncedInstance<PluginConfig> {
 | |
|     
 | |
|     public abstract class NumberRange<T> {
 | |
|       private string name;
 | |
|       [SerializeField] protected T _min;
 | |
|       [SerializeField] protected T _max;
 | |
| 
 | |
|       public T min {
 | |
|         get {
 | |
|           return _min;
 | |
|         } set {
 | |
|           _min = value;
 | |
|           Verify();
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       public T max {
 | |
|         get {
 | |
|           return _max;
 | |
|         } set {
 | |
|           _max = value;
 | |
|           Verify();
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       public NumberRange(string name){
 | |
|         this.name = name;
 | |
|         _min = default;
 | |
|         _max = default;
 | |
|       }
 | |
| 
 | |
|       public virtual void Verify(){
 | |
|         Plugin.logger.LogDebug($"Verifying min/max for {name}");
 | |
|       }
 | |
| 
 | |
|       public override string ToString() {
 | |
|         return $"({min}, {max})";
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class IntRange : NumberRange<int> {
 | |
| 
 | |
|       public IntRange(string name) : base(name) { }
 | |
| 
 | |
|       public override void Verify() {
 | |
|         base.Verify();
 | |
|         _max = Mathf.Max(_min, _max);
 | |
|       }
 | |
| 
 | |
|       public DunGen.IntRange GetDungenIntRange(){
 | |
|         return new DunGen.IntRange(min, max);
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class FloatRange : NumberRange<float> {
 | |
| 
 | |
|       public FloatRange(string name) : base(name) { }
 | |
| 
 | |
|       public override void Verify() {
 | |
|         base.Verify();
 | |
|         _max = Mathf.Max(_min, _max);
 | |
|       }
 | |
| 
 | |
|       public DunGen.FloatRange GetDungenFloatRange(){
 | |
|         return new DunGen.FloatRange(min, max);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class BranchingPathRange {
 | |
|       private string name;
 | |
|       public IntRange count;
 | |
|       public IntRange depth;
 | |
| 
 | |
|       public BranchingPathRange(string name){
 | |
|         this.name = name;
 | |
|         count = new IntRange($"{name} count");
 | |
|         depth = new IntRange($"{name} depth");
 | |
|       }
 | |
| 
 | |
|       public void UpdateValues(DunGen.DungeonArchetype archetype){
 | |
|         archetype.BranchCount = new DunGen.IntRange(count.min, count.max);
 | |
|         archetype.BranchingDepth = new DunGen.IntRange(depth.min, depth.max);
 | |
|       }
 | |
| 
 | |
|       public override string ToString() {
 | |
|         return $"{count.ToString()}+{depth.ToString()}";
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class Enemy {
 | |
|       public bool enabled;
 | |
|       public int health;
 | |
|       public float speed;
 | |
|     }
 | |
| 
 | |
|     [System.Serializable] 
 | |
|     public class SpawnableEnemy : Enemy {
 | |
|       public int spawnWeightBase;
 | |
|       public float spawnWeightStealPercentage;
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class Item {
 | |
|       public bool enabled;
 | |
|       public IntRange valueRange;
 | |
| 
 | |
|       public Item(string name) {
 | |
|         valueRange = new IntRange($"{name} value range");
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     [System.Serializable]
 | |
|     public class ScrapItem : Item {
 | |
|       public int spawnWeight;
 | |
|       public bool spawnOnAllMoons;
 | |
| 
 | |
|       public ScrapItem(string name) : base(name) { }
 | |
|     }
 | |
| 
 | |
|     public abstract class ConfigEntryBundleBase {
 | |
| 
 | |
|       public class FieldPropertyInfo {
 | |
|         public FieldInfo fieldInfo;
 | |
|         public PropertyInfo propertyInfo;
 | |
| 
 | |
|         public FieldPropertyInfo(FieldInfo fieldInfo){
 | |
|           this.fieldInfo = fieldInfo;
 | |
|         }
 | |
| 
 | |
|         public FieldPropertyInfo(PropertyInfo propertyInfo){
 | |
|           this.propertyInfo = propertyInfo;
 | |
|         }
 | |
| 
 | |
|         public void SetValue(object obj, object value){
 | |
|           if (fieldInfo != null) fieldInfo.SetValue(obj, value);
 | |
|           if (propertyInfo != null) propertyInfo.SetValue(obj, value);
 | |
|         }
 | |
| 
 | |
|         public object GetValue(object obj){
 | |
|           if (fieldInfo != null) return fieldInfo.GetValue(obj);
 | |
|           if (propertyInfo != null) return propertyInfo.GetValue(obj);
 | |
|           return null;
 | |
|         }
 | |
| 
 | |
|         public Type GetFieldPropertyType(){
 | |
|           if (fieldInfo != null) return fieldInfo.FieldType;
 | |
|           if (propertyInfo != null) return propertyInfo.PropertyType;
 | |
|           return null;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       public abstract IEnumerable<ConfigEntryBase> GetConfigs();
 | |
|       public abstract void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget);
 | |
| 
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleExtraParameters {
 | |
|       public Action<PluginConfig> onSettingsChanged;
 | |
|       public bool callOnBind;
 | |
| 
 | |
|       public ConfigEntryBundleExtraParameters(Action<PluginConfig> onSettingsChanged, bool callOnBind){
 | |
|         this.onSettingsChanged = onSettingsChanged;
 | |
|         this.callOnBind = callOnBind;
 | |
|       }
 | |
| 
 | |
|       public void CallAction(PluginConfig instance, bool isBind){
 | |
|        if (isBind && !callOnBind) return;
 | |
|        onSettingsChanged?.Invoke(instance);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundle<T> : ConfigEntryBundleBase {
 | |
|       public ConfigEntry<T> config;
 | |
|       public ConfigDefinition definition;
 | |
|       public T defaultValue;
 | |
|       public ConfigDescription description;
 | |
|       public ConfigEntryBundleExtraParameters extra;
 | |
| 
 | |
|       public ConfigEntryBundle(string section, string key, T dvalue, string desc, ConfigEntryBundleExtraParameters extra = null, AcceptableValueBase valuebase = null){
 | |
|         definition = new ConfigDefinition(section, key);
 | |
|         defaultValue = dvalue;
 | |
|         description = new ConfigDescription(desc, valuebase);
 | |
| 
 | |
|         if (extra == null) extra = new ConfigEntryBundleExtraParameters(null, false);
 | |
|         this.extra = extra;
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         config = cfg.Bind(definition, defaultValue, description);
 | |
|         config.SettingChanged += (obj, args) => {
 | |
|           Plugin.logger.LogDebug($"Config settings {config.Definition.Key} changed");
 | |
|           memberInfo.SetValue(memberTarget, config.Value);
 | |
|           extra.CallAction(instance, false);
 | |
|         };
 | |
| 
 | |
|         memberInfo.SetValue(memberTarget, config.Value);
 | |
|         extra.CallAction(instance, true);
 | |
|       }
 | |
| 
 | |
|       public void Bind(ConfigFile cfg, PluginConfig instance){
 | |
|         config = cfg.Bind(definition, defaultValue, description);
 | |
|         config.SettingChanged += (obj, args) => {
 | |
|           Plugin.logger.LogDebug($"Config settings {config.Definition.Key} changed");
 | |
|           extra.CallAction(instance, false);
 | |
|         };
 | |
|         
 | |
|         extra.CallAction(instance, true);
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         yield return config;
 | |
|       }
 | |
| 
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleMinMax<T> : ConfigEntryBundleBase {
 | |
|       public ConfigEntryBundle<T> min;
 | |
|       public ConfigEntryBundle<T> max;
 | |
| 
 | |
|       public ConfigEntryBundleMinMax(string section, string keyMin, string keyMax, T defaultValueMin, T defaultValueMax, string descMin, string descMax, ConfigEntryBundleExtraParameters extra = null,  AcceptableValueBase valuebase = null){
 | |
|         min = new ConfigEntryBundle<T>(section, keyMin, defaultValueMin, descMin, extra, valuebase);
 | |
|         max = new ConfigEntryBundle<T>(section, keyMax, defaultValueMax, descMax, extra, valuebase);
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var minProp = type.GetProperty("min", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var maxProp = type.GetProperty("max", BindingFlags.Public | BindingFlags.Instance);
 | |
|         min.Bind(cfg, instance, new FieldPropertyInfo(minProp), memberInfo.GetValue(memberTarget));
 | |
|         max.Bind(cfg, instance, new FieldPropertyInfo(maxProp), memberInfo.GetValue(memberTarget));
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         yield return min.config;
 | |
|         yield return max.config;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleBranchingPath : ConfigEntryBundleBase {
 | |
|       public ConfigEntryBundleMinMax<int> count;
 | |
|       public ConfigEntryBundleMinMax<int> depth;
 | |
| 
 | |
|       public ConfigEntryBundleBranchingPath(string section, int sectionId, string extraMessage, int countMinValue, int countMaxValue, int depthMinValue, int depthMaxValue, ConfigEntryBundleExtraParameters extra = null){
 | |
|         count = new ConfigEntryBundleMinMax<int>(
 | |
|           section,
 | |
|           $"Section {sectionId} Count Min",
 | |
|           $"Section {sectionId} Count Max",
 | |
|           countMinValue,
 | |
|           countMaxValue,
 | |
|           _branchPathBranchCountMessage(sectionId, "minimum", extraMessage),
 | |
|           _branchPathBranchCountMessage(sectionId, "maximum", extraMessage),
 | |
|           extra,
 | |
|           new AcceptableValueRange<int>(0, 20)
 | |
|         );
 | |
| 
 | |
|         depth = new ConfigEntryBundleMinMax<int>(
 | |
|           section,
 | |
|           $"Section {sectionId} Depth Min",
 | |
|           $"Section {sectionId} Depth Max",
 | |
|           depthMinValue,
 | |
|           depthMaxValue,
 | |
|           _branchPathBranchDepthMessage(sectionId, "minimum", extraMessage),
 | |
|           _branchPathBranchDepthMessage(sectionId, "maximum", extraMessage),
 | |
|           extra,
 | |
|           new AcceptableValueRange<int>(0, 20)
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var countField = type.GetField("count", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var depthField = type.GetField("depth", BindingFlags.Public | BindingFlags.Instance);
 | |
|         count.Bind(cfg, instance, new FieldPropertyInfo(countField), memberInfo.GetValue(memberTarget));
 | |
|         depth.Bind(cfg, instance, new FieldPropertyInfo(depthField), memberInfo.GetValue(memberTarget));
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         foreach(var a in count.GetConfigs()) {
 | |
|           yield return a;
 | |
|         }
 | |
| 
 | |
|         foreach(var a in depth.GetConfigs()) {
 | |
|           yield return a;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleEnemy : ConfigEntryBundleBase {
 | |
|       public ConfigEntryBundle<bool> enabled;
 | |
|       public ConfigEntryBundle<int> health;
 | |
|       public ConfigEntryBundle<float> speed;
 | |
|       
 | |
|       public ConfigEntryBundleEnemy(string section, string enemyName, int baseHealth, float baseSpeed, ConfigEntryBundleExtraParameters extra = null){
 | |
|         var enabledDesc = $"If disabled, {enemyName} is disabled from spawning.";
 | |
|         var healthDesc = $"The health of the {enemyName}. A shovel is 1 damage.";
 | |
|         var speedDesc = $"The speed of the {enemyName} during their killing/aggressive stance. The player's default speed is 4.6.";
 | |
| 
 | |
|         enabled = new ConfigEntryBundle<bool>(section, "Enabled", true, enabledDesc, extra);
 | |
|         health = new ConfigEntryBundle<int>(section, "Health", baseHealth, healthDesc, extra, new AcceptableValueRange<int>(1, 20));
 | |
|         speed = new ConfigEntryBundle<float>(section, "Speed", baseSpeed, speedDesc, extra,  new AcceptableValueRange<float>(1f, 20f));
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var enabledProp = type.GetField("enabled", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var healthProp = type.GetField("health", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var speedProp = type.GetField("speed", BindingFlags.Public | BindingFlags.Instance);
 | |
|         
 | |
|         enabled.Bind(cfg, instance, new FieldPropertyInfo(enabledProp), memberInfo.GetValue(memberTarget));
 | |
|         if (health.defaultValue > 0) health.Bind(cfg, instance, new FieldPropertyInfo(healthProp), memberInfo.GetValue(memberTarget));
 | |
|         speed.Bind(cfg, instance, new FieldPropertyInfo(speedProp), memberInfo.GetValue(memberTarget));
 | |
|         
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         yield return enabled.config;
 | |
|         if (health.defaultValue > 0) yield return health.config;
 | |
|         yield return speed.config;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleSpawnableEnemy : ConfigEntryBundleEnemy {
 | |
|       public ConfigEntryBundle<int> spawnWeightBase;
 | |
|       public ConfigEntryBundle<float> spawnWeightStealPercentage;
 | |
| 
 | |
|       public ConfigEntryBundleSpawnableEnemy(string section, string enemyName, string replacementEnemyName, int baseHealth, float baseSpeed, ConfigEntryBundleExtraParameters extra = null) : base(section, enemyName, baseHealth, baseSpeed, extra) {
 | |
| 
 | |
|         var weightBaseDesc = $"The base spawn weight of the {enemyName}. This is added onto the spawn weight stolen from the {replacementEnemyName}, or the base weight of 10 if the moon doesn't spawn the {replacementEnemyName}.";
 | |
|         var weightStealPercentageDesc = $"The percentage of spawn weight that the {enemyName} steals from the {replacementEnemyName} for that moon.\nSetting this 0 means that the {replacementEnemyName}'s weight is unaffected and the {enemyName}'s weight is based entirely by Spawn Weight Base.\nSetting this 1 means the {enemyName} effectively replaces the {replacementEnemyName}.";
 | |
|         
 | |
|         spawnWeightBase = new ConfigEntryBundle<int>(section, "Spawn Weight Base", 0, weightBaseDesc, extra, new AcceptableValueRange<int>(0, 999));
 | |
|         spawnWeightStealPercentage = new ConfigEntryBundle<float>(section, "Spawn Weight Steal Percentage", 0.75f, weightStealPercentageDesc, extra,  new AcceptableValueRange<float>(0f, 1f));
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         base.Bind(cfg, instance, memberInfo, memberTarget);
 | |
| 
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var weightBaseProp = type.GetField("spawnWeightBase", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var weightStealPercentageProp = type.GetField("spawnWeightStealPercentage", BindingFlags.Public | BindingFlags.Instance);
 | |
| 
 | |
|         spawnWeightBase.Bind(cfg, instance, new FieldPropertyInfo(weightBaseProp), memberInfo.GetValue(memberTarget));
 | |
|         spawnWeightStealPercentage.Bind(cfg, instance, new FieldPropertyInfo(weightStealPercentageProp), memberInfo.GetValue(memberTarget));
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         foreach(var a in base.GetConfigs()) {
 | |
|           yield return a;
 | |
|         }
 | |
|         yield return spawnWeightBase.config;
 | |
|         yield return spawnWeightStealPercentage.config;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleItem : ConfigEntryBundleBase {
 | |
|       public ConfigEntryBundle<bool> enabled;
 | |
|       public ConfigEntryBundleMinMax<int> valueRange;
 | |
|       
 | |
|       private static string _valueMessage(string itemName, string minmax) => $"The {minmax} scrap value of {itemName}. Lethal Company multiplies all scrap values by 0.4.";
 | |
| 
 | |
|       public ConfigEntryBundleItem(string section, string keyPrefix, string itemName, int baseValueMin, int baseValueMax, ConfigEntryBundleExtraParameters extra = null){
 | |
|         var enabledDesc = $"If disabled, {itemName} is disabled from spawning.";
 | |
| 
 | |
|         enabled = new ConfigEntryBundle<bool>(section, $"{keyPrefix}Enabled", true, enabledDesc, extra);
 | |
|         valueRange = new ConfigEntryBundleMinMax<int>(
 | |
|         section,
 | |
|           $"Value Min",
 | |
|           $"Value Max",
 | |
|           baseValueMin,
 | |
|           baseValueMax,
 | |
|           _valueMessage(itemName, "minimum"),
 | |
|           _valueMessage(itemName, "maximum"),
 | |
|           extra,
 | |
|           new AcceptableValueRange<int>(1, 400)
 | |
|         );
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var enabledProp = type.GetField("enabled", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var valueRangeProp = type.GetField("valueRange", BindingFlags.Public | BindingFlags.Instance);
 | |
|         
 | |
|         enabled.Bind(cfg, instance, new FieldPropertyInfo(enabledProp), memberInfo.GetValue(memberTarget));
 | |
|         if (valueRange.min.defaultValue > 0) valueRange.Bind(cfg, instance, new FieldPropertyInfo(valueRangeProp), memberInfo.GetValue(memberTarget));
 | |
|         
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         yield return enabled.config;
 | |
|         if (valueRange.min.defaultValue > 0) {
 | |
|           foreach(var a in valueRange.GetConfigs()) {
 | |
|             yield return a;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     public class ConfigEntryBundleScrapItem : ConfigEntryBundleItem {
 | |
|       public ConfigEntryBundle<int> spawnWeight;
 | |
|       public ConfigEntryBundle<bool> spawnOnAllMoons;
 | |
| 
 | |
|       public ConfigEntryBundleScrapItem(string section, string itemName, int baseValueMin, int baseValueMax, int baseSpawnWeight, ConfigEntryBundleExtraParameters extra = null) : base(section, string.Empty, itemName, baseValueMin, baseValueMax, extra) {
 | |
| 
 | |
|         var weightDesc = $"The {itemName}'s spawn weight. Calculating spawn chance (%) is difficult as the total scrap weight for each moon varies from ~600 to ~850.";
 | |
|         var spawnDesc = $"If enabled, the {itemName} scrap item will spawn on all moons regardless if SDM loaded.";
 | |
|         
 | |
|         spawnWeight = new ConfigEntryBundle<int>(section, "Spawn Weight Base", baseSpawnWeight, weightDesc, extra, new AcceptableValueRange<int>(0, 999));
 | |
|         spawnOnAllMoons = new ConfigEntryBundle<bool>(section, "Spawn On All Moons", false, spawnDesc, extra);
 | |
|       }
 | |
| 
 | |
|       public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
 | |
|         base.Bind(cfg, instance, memberInfo, memberTarget);
 | |
| 
 | |
|         var type = memberInfo.GetFieldPropertyType();
 | |
|         var weightDescProp = type.GetField("spawnWeight", BindingFlags.Public | BindingFlags.Instance);
 | |
|         var spawnDescProp = type.GetField("spawnOnAllMoons", BindingFlags.Public | BindingFlags.Instance);
 | |
| 
 | |
|         spawnWeight.Bind(cfg, instance, new FieldPropertyInfo(weightDescProp), memberInfo.GetValue(memberTarget));
 | |
|         spawnOnAllMoons.Bind(cfg, instance, new FieldPropertyInfo(spawnDescProp), memberInfo.GetValue(memberTarget));
 | |
|       }
 | |
| 
 | |
|       public override IEnumerable<ConfigEntryBase> GetConfigs() {
 | |
|         foreach(var a in base.GetConfigs()) {
 | |
|           yield return a;
 | |
|         }
 | |
|         yield return spawnWeight.config;
 | |
|         yield return spawnOnAllMoons.config;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|   }
 | |
| }
 |