From 7f6b28e081f91e4c0b489bd45f7e7ac305b847ed Mon Sep 17 00:00:00 2001 From: GrahamKracker Date: Sun, 11 Jun 2023 03:33:11 -0400 Subject: [PATCH] major changes --- Extensions.cs | 14 +- LATEST.md | 14 +- Merging/Algorithm.cs | 864 +++--------------- Merging/MergeFixes/FixAbilities.cs | 8 +- Merging/MergeFixes/FixAdoraSacrifice.cs | 6 +- Merging/MergeFixes/FixAdvancedIntel.cs | 12 +- Merging/MergeFixes/FixAirUnits.cs | 106 --- Merging/MergeFixes/FixAircraftCarriers.cs | 67 +- Merging/MergeFixes/FixAutoCollectings.cs | 6 +- Merging/MergeFixes/FixBananas.cs | 26 - Merging/MergeFixes/FixBehaviorNames.cs | 4 +- Merging/MergeFixes/FixCamo.cs | 34 +- Merging/MergeFixes/FixCannonShips.cs | 17 +- Merging/MergeFixes/FixClusterMauling.cs | 8 +- Merging/MergeFixes/FixGlueOverriding.cs | 22 +- Merging/MergeFixes/FixHeroVoicelines.cs | 14 + Merging/MergeFixes/FixHeroes.cs | 14 +- Merging/MergeFixes/FixHomingProjectiles.cs | 4 +- Merging/MergeFixes/FixIceMonkeyRange.cs | 6 +- Merging/MergeFixes/FixLifespans.cs | 5 +- Merging/MergeFixes/FixPlasmaBeams.cs | 12 +- Merging/MergeFixes/FixRoboMonkeys.cs | 45 + Merging/MergeFixes/FixSmallRanges.cs | 13 +- Merging/MergeFixes/FixSpectre.cs | 8 +- Merging/MergeFixes/FixSpikeStorm.cs | 26 - Merging/MergeFixes/FixTemples.cs | 13 +- Merging/MergeFixes/PostMergeFix.cs | 5 +- .../SimulationFixes/AnotherAirUnitModelFix.cs | 16 - Merging/SimulationFixes/SimulationFix.cs | 4 +- ModHelperData.cs | 4 +- ModelBehaviorExt.cs | 1 - OmegaCrosspathing.csproj | 9 +- Patches.cs | 215 +++-- UI.cs | 85 +- 34 files changed, 500 insertions(+), 1207 deletions(-) delete mode 100644 Merging/MergeFixes/FixAirUnits.cs delete mode 100644 Merging/MergeFixes/FixBananas.cs create mode 100644 Merging/MergeFixes/FixHeroVoicelines.cs create mode 100644 Merging/MergeFixes/FixRoboMonkeys.cs delete mode 100644 Merging/MergeFixes/FixSpikeStorm.cs delete mode 100644 Merging/SimulationFixes/AnotherAirUnitModelFix.cs delete mode 100644 ModelBehaviorExt.cs diff --git a/Extensions.cs b/Extensions.cs index 35b491f..f87a3e1 100644 --- a/Extensions.cs +++ b/Extensions.cs @@ -24,21 +24,9 @@ public static object GetPropertyValue(this object obj, string propertyName) throw new ArgumentNullException("obj"); Type objType = obj.GetType(); PropertyInfo propInfo = GetPropertyInfo(objType, propertyName); - if (propInfo == null) - throw new ArgumentOutOfRangeException("propertyName", - string.Format("Couldn't find property {0} in type {1}", propertyName, objType.FullName)); - return propInfo.GetValue(obj, null); - } - - public static void SetPropertyValue(this object obj, string propertyName, object val) - { - if (obj == null) - throw new ArgumentNullException(nameof(obj)); - Type objType = obj.GetType(); - PropertyInfo propInfo = GetPropertyInfo(objType, propertyName); if (propInfo == null) throw new ArgumentOutOfRangeException("propertyName", $"Couldn't find property {propertyName} in type {objType.FullName}"); - propInfo.SetValue(obj, val, null); + return propInfo.GetValue(obj, null); } } \ No newline at end of file diff --git a/LATEST.md b/LATEST.md index e4c74a5..6eb65db 100644 --- a/LATEST.md +++ b/LATEST.md @@ -1,5 +1,9 @@ -Fixed etienne/wizard lord pheonix spawning infinite sub towers (thanks @doombubbles!) -Removed adora's blood sacrifice from being merged -Stopped Geraldo from appearing since he didnt work -Fixed some issues after leaving match and starting a new one -Fixed UI appearing over vanilla ui, when it shouldnt \ No newline at end of file +Fixed an issue with showing paths-plus-plus added paths behind the ui +Created a new algorithm for merging, should have results that are less focused on "crosspathing" and more on merging +Added a toggle to the tower selection menu allowing you to toggle between vanilla and oc ui +Fixed paths-plus-plus upgrades not getting properly cleared and applying to newly placed towers +Now actually saves paths-plus-plus merged upgrades +Fixed tower highlighting getting removed after merging +Stopped hero voicelines from playing on merged towers +Fixed some issues with merging 000 towers +Fixed UI sometimes appearing on paragons \ No newline at end of file diff --git a/Merging/Algorithm.cs b/Merging/Algorithm.cs index 41d8eac..50b1ebf 100644 --- a/Merging/Algorithm.cs +++ b/Merging/Algorithm.cs @@ -1,4 +1,4 @@ -using System.Collections.Generic; +using System.Collections.Generic; using BTD_Mod_Helper.Api; using Il2Cpp; using Il2CppAssets.Scripts.Models; @@ -6,56 +6,49 @@ using Il2CppAssets.Scripts.Models.Towers.Behaviors.Abilities; using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack; using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack.Behaviors; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Emissions; using Il2CppAssets.Scripts.Models.Towers.Filters; using Il2CppAssets.Scripts.Models.Towers.Projectiles; using Il2CppAssets.Scripts.Models.Towers.Weapons; using Il2CppInterop.Runtime; +using Il2CppInterop.Runtime.InteropTypes.Arrays; +using Il2CppSystem; using Il2CppSystem.Reflection; using OmegaCrosspathing.Merging.MergeFixes; -using Array = Il2CppSystem.Array; -using Exception = System.Exception; -using Math = System.Math; -using Object = Il2CppSystem.Object; -using Type = Il2CppSystem.Type; namespace OmegaCrosspathing.Merging; public static class Algorithm { - public static void Merge(TowerModel first, TowerModel? second) + public static void Merge(TowerModel first, TowerModel second) { - if (second == null) + first.range = Average(first.range, second.range); + + if (second.mods is not null) { - return; + first.mods = first.mods.Union(second.mods).ToArray(); } - second = second.Duplicate(); - - first.range = (first.range + second.range) / 2; - - first.mods = first.mods.Union(second.mods).ToArray(); - - try + if (second.targetTypes is not null) { - var footprintInfo = Il2CppType.Of().GetProperty("footprint"); - DeepMerge(footprintInfo, first, second, null); - first.targetTypes = first.targetTypes.Union(second.targetTypes).ToArray(); + } - first.towerSize = (TowerModel.TowerSize)Math.Max((int)first.towerSize, (int)second.towerSize); - + first.towerSize = (TowerModel.TowerSize)Math.Max((int)first.towerSize, (int)second.towerSize); + + if (second.appliedUpgrades is not null) + { first.appliedUpgrades = first.appliedUpgrades.Union(second.appliedUpgrades).ToArray(); } - catch (Exception e) + + foreach (var child in first.behaviors) { - MelonLogger.Error("Error during non-crucial merges"); - MelonLogger.Warning(e); + first.RemoveChildDependant(child); + } + first.behaviors = MergeBehaviors(first.behaviors, second.behaviors); + foreach (var child in first.behaviors) + { + first.AddChildDependant(child); } - - var behaviorsInfo = Il2CppType.Of().GetField("behaviors"); - MergeField(behaviorsInfo, first, second, null); - foreach (var postMergeFix in ModContent.GetContent()) { @@ -64,7 +57,7 @@ public static void Merge(TowerModel first, TowerModel? second) postMergeFix.Apply(first); postMergeFix.Apply(first, second); } - catch (Exception e) + catch (System.Exception e) { MelonLogger.Error("Error during postmergefix: " + postMergeFix.Name + ", but thanks to this message, the crisis has been averted :)"); MelonLogger.Warning(e); @@ -72,8 +65,7 @@ public static void Merge(TowerModel first, TowerModel? second) } } - - public static readonly HashSet DontMerge = new() + private static readonly HashSet DontMerge = new() { "animation", "offsetX", @@ -82,674 +74,158 @@ public static void Merge(TowerModel first, TowerModel? second) "ejectX", "ejectY", "ejectZ", - "rate", "rateFrames", "isPowerTower", "isGeraldoItem" }; - public static readonly HashSet Multiplicative = new() - { - "pierce", - "range" - }; - - public static readonly Dictionary StringOverrides = new() + private static readonly Dictionary, bool> BoolOverrides = new() { - { "fcddee8a92f5d2e4d8605a8924566620", "69bf8d5932f2bea4f9ce36f861240d2e" }, //DartMonkey-340 - { "0ddd8752be0d3554cb0db6abe6686e8e", "69bf8d5932f2bea4f9ce36f861240d2e" } //DartMonkey-043 + { new Tuple("isActive", Il2CppType.Of()), false }, + { new Tuple("ignoreBlockers", Il2CppType.Of()), true }, + { new Tuple("isSharedRangeEnabled", Il2CppType.Of()), true }, }; - public static readonly Dictionary<(string, Type), bool> BetterBooleans = new() + public static Il2CppReferenceArray MergeBehaviors(Il2CppReferenceArray first, Il2CppReferenceArray second) { - { ("isActive", Il2CppType.Of()), false }, - { ("ignoreBlockers", Il2CppType.Of()), true }, - { ("isSharedRangeEnabled", Il2CppType.Of()), true }, - }; - - public static Object DeepMerge(Object left, Object right, Object ancestor, History history, - bool shallow = false) - { - if (right is null) - { - return left; - } + var firstBehaviors = first.ToList(); - if (left is null) + foreach (var secondbehavior in second.Where(x => firstBehaviors.FirstOrDefault(y => IsSameModel(y, x)) is not null)) { - return right; - } - - history.Push(left, right, ancestor); - - try - { - // Without this, there is inconsistent handling of the WeaponModels rate and rateFrames fields - if (left.IsType(out var leftWeapon) - && right.IsType(out var rightWeapon) - && ancestor != null && ancestor.IsType(out var ancestorWeapon)) + var firstBehavior = firstBehaviors.First(x => IsSameModel(x, secondbehavior)); + foreach (var field in secondbehavior.GetIl2CppType().GetFields().Where(x=> !DontMerge.Any(dontmerge=> x.Name.Contains(dontmerge)))) { - leftWeapon.Rate *= rightWeapon.Rate / ancestorWeapon.Rate; + MergeTypes(field.FieldType, field, secondbehavior, firstBehavior); } - if (left.IsType(out var leftModel) && right.IsType(out var rightModel) && - !(ModelsAreTheSame(leftModel, rightModel, false, history) || shallow)) + foreach (var property in secondbehavior.GetIl2CppType().GetProperties().Where(property => property.CanWrite && !DontMerge.Any(dontmerge => property.Name.Contains(dontmerge) && property.Name.ToUpper()[0] != property.Name[0]))) { - return MergeDifferentModels(left, right, ancestor, history); + MergeTypes(property.PropertyType, property, secondbehavior, firstBehavior); } - - var leftFields = left.GetIl2CppType().GetFields(); - foreach (var fieldInfo in leftFields) - { - var fieldName = fieldInfo.Name; - - if (DontMerge.Any(s => fieldName.Contains(s))) continue; - - MergeField(fieldInfo, left, right, ancestor, history, shallow); - } - - var leftProperties = left.GetIl2CppType().GetProperties(); - foreach (var propertyInfo in leftProperties) - { - var propertyName = propertyInfo.Name; - - if (propertyName.ToUpper()[0] == propertyName[0] || DontMerge.Any(s => propertyName.Contains(s))) - { - //skip capitalized ones, they seem like weird ones - continue; - } - - MergeField(propertyInfo, left, right, ancestor, history, shallow); - } - - return left; } - finally + + foreach (var behavior in second.Where(x => firstBehaviors.FirstOrDefault(y => IsSameModel(y, x)) is null)) { - history.Pop(); + //MelonLogger.Msg("Adding behavior: " + behavior.name + " as " + behavior.GetIl2CppType().FullName); + firstBehaviors.Add(behavior); } + + return firstBehaviors.ToIl2CppReferenceArray(); } - public static void MergeField(MemberInfo memberInfo, Object left, Object right, Object ancestor, - History history = null, bool shallow = false) + private static bool IsType(this Type typ) { - var memberType = memberInfo.Type(); - var leftValue = memberInfo.GetValue(left); - var rightValue = memberInfo.GetValue(right); - - if (history == null) - { - history = new History(); - history.Push(left, right, ancestor); - } - - Log($"{memberInfo.Name} ({memberType.Name})", history.Depth); - - Object ancestorValue = null; - if (ancestor != null && ancestor.GetIl2CppType().GetMember(memberInfo.Name).Length > 0) - { - ancestorValue = memberInfo.GetValue(ancestor); - } - - if (leftValue == null && rightValue == null) - { - return; - } - - if (memberType.IsArray) - { - memberInfo.SetValue(left, - MergeArray(memberInfo, leftValue, rightValue, ancestorValue, history, shallow)); - } - else if (memberType.IsType()) - { - memberInfo.SetValue(left, MergeFloat(memberInfo, leftValue, rightValue, ancestorValue)); - } - else if (memberType.IsType()) - { - memberInfo.SetValue(left, MergeInt(memberInfo, leftValue, rightValue, ancestorValue)); - } - else if (memberType.IsType()) - { - memberInfo.SetValue(left, MergeBool(memberInfo, leftValue, rightValue, history)); - } - else if (memberType.IsType()) - { - memberInfo.SetValue(left, DeepMerge(leftValue, rightValue, ancestorValue, history)); - } - else if (memberType.IsType()) - { - var fieldInfo = memberInfo.TryCast(); - if (fieldInfo == null || (!fieldInfo.IsLiteral && !fieldInfo.IsInitOnly)) - { - memberInfo.SetValue(left, MergeString(memberInfo, leftValue, rightValue, ancestorValue)); - } - } - else if (memberType.IsType()) - { - var leftProps = leftValue.Unbox(); - var rightProps = rightValue.Unbox(); - var result = (int)(leftProps & rightProps); - memberInfo.SetValue(left, result.ToIl2Cpp()); - } + var ty = Il2CppType.From(typeof(T)); + return ty.IsAssignableFrom(typ); } - public static Object MergeArray(MemberInfo memberInfo, Object left, Object right, Object ancestor, - History history, bool shallow = false) + private static void MergeTypes(Type memberType, MemberInfo member, Object firstBehavior, Object secondbehavior) { - if (left == null && right != null) - { - return right; - } - - if (right == null && left != null) - { - return left; - } - - history.Depth++; - var elementType = memberInfo.Type().GetElementType(); - var stuff = new List(); - - var leftStuff = new List(); - foreach (var o in left.Cast()) - { - leftStuff.Add(o); - } - - var rightStuff = new List(); - foreach (var o in right.Cast()) - { - rightStuff.Add(o); - } - - var ancestorStuff = new List(); - if (ancestor != null) - { - foreach (var o in ancestor.Cast()) - { - ancestorStuff.Add(o); - } - } - - - if (elementType.IsType()) + switch (memberType) { - foreach (var leftThing in leftStuff) - { - var leftModel = leftThing.Cast(); - - var rightModel = rightStuff - .Select(rightThing => rightThing.Cast()) - .FirstOrDefault(model => ModelsAreTheSame(leftModel, model, true, history)); - - if (rightModel != null && !shallow) - { - var ancestorModel = ancestorStuff - .Select(ancestorThing => ancestorThing.Cast()) - .FirstOrDefault(model => ModelsAreTheSame(leftModel, model, true, history)); - - Log($"{leftModel.name} ({leftModel.GetIl2CppType().Name})", history.Depth); - - DeepMerge(leftModel, rightModel, ancestorModel, history); - } - - stuff.Add(leftModel); - - - if (leftModel.IsType(out var attackModel)) // Newly added attacks + case not null when memberType.IsType(): + if (secondbehavior.IsType(out var secondWeaponModel) && firstBehavior.IsType(out var firstWeaponModel) && member.Name == "rate") { - var leftTowerModel = history.GetLeft(); - var rightTowerModel = history.GetRight(); - if (Math.Abs(rightTowerModel.range - attackModel.range) < 1e7 && - leftTowerModel.range > rightTowerModel.range) - { - attackModel.range = Math.Max(leftTowerModel.range, attackModel.range); - } + member.SetValue(firstBehavior,firstWeaponModel.rate * secondWeaponModel.rate); + break; } - } - - foreach (var rightThing in rightStuff) - { - var rightModel = rightThing.Cast(); - - var leftModel = leftStuff - .Select(leftThing => leftThing.Cast()) - .FirstOrDefault(model => ModelsAreTheSame(model, rightModel, true, history)); - - if (leftModel == null) + member.SetValue(firstBehavior, + Average(member.GetValue(firstBehavior).Unbox(), + member.GetValue(secondbehavior).Unbox())); + break; + case not null when memberType.IsType(): + member.SetValue(firstBehavior, + (int)Average(member.GetValue(firstBehavior).Unbox(), + member.GetValue(secondbehavior).Unbox())); + break; + case not null when memberType.IsType(): + var firstBool = member.GetValue(firstBehavior).Unbox(); + var secondBool = member.GetValue(secondbehavior).Unbox(); + foreach (var ((name, type), value) in BoolOverrides) { - stuff.Add(rightModel); - var peek = history.left.Peek(); - if (peek != null && peek.IsType(out var model)) + if (member.Name.Contains(name)) { - model.AddChildDependant(rightModel); - } - - - if (rightModel.IsType(out var attackModel)) // Newly added attacks - { - var leftTowerModel = history.GetLeft(); - var rightTowerModel = history.GetRight(); - if (Math.Abs(rightTowerModel.range - attackModel.range) < 1e7 && - leftTowerModel.range > rightTowerModel.range) + if (firstBehavior.GetIl2CppType().IsSubclassOf(type)) { - attackModel.range = Math.Max(leftTowerModel.range, attackModel.range); + member.SetValue(firstBehavior, value.ToIl2Cpp()); + break; } } - } - //todo: this is what will probably break - else - { - leftModel.AddChildDependant(rightModel); - } - } - } - else if (memberInfo.Name == "collisionPasses") - { - stuff = rightStuff.Count > leftStuff.Count ? rightStuff : leftStuff; - } - else - { - //what to do with arrays that aren't just more models? - - if (leftStuff.Count == ancestorStuff.Count && rightStuff.Count != ancestorStuff.Count) - { - stuff = rightStuff; - } - else - { - stuff = leftStuff; - } - } - - - var result = Array.CreateInstance(memberInfo.Type().GetElementType(), stuff.Count); - for (var i = 0; i < stuff.Count; i++) - { - result.SetValue(stuff[i], i); - } - - history.Depth--; - return result; - } - - /// - /// Merge two integers with respect to a common ancestor - /// - /// - /// - /// - /// - /// - public static Object MergeInt(MemberInfo memberInfo, Object leftValue, Object rightValue, Object ancestorValue) - { - if (leftValue == null) - { - return rightValue; - } - - if (rightValue == null) - { - return leftValue; - } - - var leftInt = leftValue.Unbox(); - var rightInt = rightValue.Unbox(); - - - if (ancestorValue != null && leftInt != rightInt) - { - var ancestorInt = ancestorValue.Unbox(); - - if (Multiplicative.Any(s => memberInfo.Name.Contains(s))) - { - leftInt = leftInt * rightInt / ancestorInt; - } - else - { - leftInt += rightInt - ancestorInt; - } - } - - return leftInt.ToIl2Cpp(); - } - - /// - /// Merge two floats with respect to a common ancestor - /// - /// - /// - /// - /// - /// - public static Object MergeFloat(MemberInfo memberInfo, Object leftValue, Object rightValue, - Object ancestorValue) - { - if (leftValue == null) - { - return rightValue; - } - - if (rightValue == null) - { - return leftValue; - } - - var leftFloat = leftValue.Unbox(); - var rightFloat = rightValue.Unbox(); - - if (ancestorValue != null && Math.Abs(leftFloat - rightFloat) > 1e-7) - { - var ancestorFloat = ancestorValue.Unbox(); - - if (Multiplicative.Any(s => memberInfo.Name.Contains(s))) - { - leftFloat *= rightFloat / ancestorFloat; - } - else - { - leftFloat += rightFloat - ancestorFloat; - } - } - - return leftFloat.ToIl2Cpp(); - } - - - /// - /// Merge two booleans with respect to a common ancestor - /// - /// - /// - /// - /// - /// - public static Object MergeBool(MemberInfo memberInfo, Object leftValue, Object rightValue, History history) - { - if (leftValue == null) - { - return rightValue; - } - - if (rightValue == null) - { - return leftValue; - } - - var fieldName = memberInfo.Name; - var leftBool = leftValue.Unbox(); - var rightBool = rightValue.Unbox(); - - if (leftBool != rightBool) - { - foreach (var ((name, type), value) in BetterBooleans) - { - if (fieldName.Contains((string)name)) - { - if (history.GetLeft().GetIl2CppType().IsSubclassOf(type)) + else { - return value.ToIl2Cpp(); + member.SetValue(firstBehavior, firstBool || secondBool); + break; } } - } - } - return leftBool.ToIl2Cpp(); - } - - - /// - /// Merge two strings with respect to a common ancestor - /// - /// - /// - /// - /// - /// - public static Object MergeString(MemberInfo memberInfo, Object leftValue, Object rightValue, - Object ancestorValue) - { - try - { - if (leftValue == null) + break; + case not null when memberType.IsType>(): { - return rightValue; - } - - if (rightValue == null) - { - return leftValue; - } - - var leftString = leftValue.ToString(); - var rightString = rightValue.ToString(); - - - if (StringOverrides.ContainsKey(leftString) && StringOverrides[leftString] == rightString) - { - return leftString; - } - - if (StringOverrides.ContainsKey(rightString) && StringOverrides[rightString] == leftString) - { - return rightString; - } - - if (ancestorValue != null) - { - var ancestorString = ancestorValue.ToString(); - - if (leftString == ancestorString && rightString != ancestorString) + var secondArray = member.GetValue(secondbehavior)?.Cast>(); + var firstArray = member.GetValue(firstBehavior)?.Cast>(); + if (secondArray is null || firstArray is null) { - return rightValue; + return; } - } - } - catch (Exception e) - { - throw new Exception($"Failed to merge strings for {memberInfo.Name}", e); - } - - - return leftValue; - } - - - /// - /// Attempt to merge two different Model objects that are not the same type - /// - /// - /// - /// - /// - /// - public static Object MergeDifferentModels(Object left, Object right, Object ancestor, History history) - { - var leftModel = left.Cast(); - var rightModel = right.Cast(); - Model ancestorModel = null; - if (ancestor != null) - { - ancestorModel = ancestor.Cast(); - } - if (leftModel.IsType(out var leftEmission) && - rightModel.IsType(out var rightEmission)) - { - if (rightModel.IsType()) - { - return rightModel; - } + var mergedArray = MergeBehaviors(firstArray, secondArray); - var leftCount = GetCountForEmissionModel(left, leftEmission); - var rightCount = GetCountForEmissionModel(right, rightEmission); - - //Ring of Fire type things - if (history.GetLeft()?.GetBehavior() != null) - { - var leftWeapon = history.GetLeft(); - var ancestorWeapon = history.GetAncestor(); - if (leftWeapon != null && ancestorWeapon != null) + var result = Array.CreateInstance(memberType.GetElementType(), mergedArray.Count); + for (var i = 0; i < mergedArray.Count; i++) { - var ancestorCount = GetCountForEmissionModel(ancestor, ancestorModel.Cast()); - - leftWeapon.projectile.GetDamageModel().damage = - (float)Math.Round( - leftWeapon.projectile.GetDamageModel().damage * rightCount / ancestorCount); - - history.GetLeft().GetBehavior() - .projectileModel = leftWeapon.projectile; + result.SetValue(mergedArray[i], i); } - return leftModel; + member.SetValue(firstBehavior, result); + break; } - - return rightCount > leftCount ? rightModel : leftModel; - } - - if (leftModel.IsType(out var leftProjectile) && - rightModel.IsType(out var rightProjectile) && - ancestorModel.IsType(out var ancestorProjectile)) - { - // Try out a shallow merge - return DeepMerge(leftModel, rightModel, ancestor, history, true); - - /*if (leftProjectile.id == ancestorProjectile.id && leftProjectile.display == - ancestorProjectile.display - && rightProjectile.id != ancestorProjectile.id && - rightProjectile.display != - ancestorProjectile.display) + case not null when memberType.IsType(): { - ModHelper.Msg("overriding projectile hmmmm"); - return rightModel; - }*/ + var result = (int)(member.GetValue(firstBehavior).Unbox() & member.GetValue(secondbehavior).Unbox()); + member.SetValue(firstBehavior, result.ToIl2Cpp()); + break; + } } - - //ModHelper.Msg($"Default merge for {leftModel.GetIl2CppType().Name} and {rightModel.GetIl2CppType().Name}"); - return leftModel; } - public static Object ShallowMerge(Object left, Object right, Object ancestor, History history) + private static Object GetValue(this MemberInfo memberInfo, Object obj) { - var leftFields = left.GetIl2CppType().GetFields(); - foreach (var memberInfo in leftFields) - { - var leftValue = memberInfo.GetValue(left); - var rightValue = memberInfo.GetValue(right); - var fieldName = memberInfo.Name; - - if (DontMerge.Any(s => fieldName.Contains(s))) continue; - if (memberInfo.Type().IsArray) - { - memberInfo.SetValue(left, MergeArray(memberInfo, leftValue, rightValue, ancestor, history, true)); - } - else - { - MergeField(memberInfo, left, right, ancestor, history); - } - } - - var leftProperties = left.GetIl2CppType().GetProperties(); - foreach (var memberInfo in leftProperties) + if (memberInfo.GetIl2CppType().IsType()) { - var leftValue = memberInfo.GetValue(left); - var rightValue = memberInfo.GetValue(right); - var propertyName = memberInfo.Name; - - if (propertyName.ToUpper()[0] == propertyName[0] || DontMerge.Any(s => propertyName.Contains(s))) - { - //skip capitalized ones, they seem like weird ones - continue; - } - - if (memberInfo.Type().IsArray) - { - memberInfo.SetValue(left, MergeArray(memberInfo, left, right, ancestor, history, true)); - } - else - { - MergeField(memberInfo, left, right, ancestor, history); - } + return memberInfo.Cast().GetValue(obj); } - return left; + return memberInfo.GetIl2CppType().IsType() ? memberInfo.Cast().GetValue(obj) : null!; } - public static int GetCountForEmissionModel(Object methodInfo, EmissionModel emissionModel) + public static void SetValue(this MemberInfo memberInfo, Object obj, Object newValue) { - var count = 1; - if (emissionModel.IsType()) - { - count = 10000; // Lines should always take priority - } - - var maybeCount = emissionModel.GetIl2CppType().GetProperty("count"); - if (maybeCount != null) - { - var value = maybeCount.GetValue(methodInfo); - if (value != null) count = value.Unbox(); - } - - var maybeCount2 = emissionModel.GetIl2CppType().GetField("count"); - if (maybeCount2 != null) + if (memberInfo.GetIl2CppType().IsType()) { - var value = maybeCount2.GetValue(methodInfo); - if (value != null) count = value.Unbox(); + memberInfo.Cast().SetValue(obj, newValue); } - - return count; - } - - public static void Log(string msg, int depth) - { - for (var i = 0; i < depth; i++) + if (memberInfo.GetIl2CppType().IsType()) { - msg = "| " + msg; + memberInfo.Cast().SetValue(obj, newValue, null); } - //ModHelper.Msg(msg); } - public static bool ModelsAreTheSame(Model leftModel, Model rightModel, bool array, History history) + private static bool IsSameModel(Model first, Model second) { - if (leftModel.IsType(out var leftAbility) && - rightModel.IsType(out var rightAbility)) + if (first.IsType(out var firstAbility) && second.IsType(out var secondAbility)) { - return leftAbility.displayName == rightAbility.displayName; + return firstAbility.displayName == secondAbility.displayName; } - - if (leftModel.IsType() && rightModel.IsType() && - leftModel.name.Contains("Create") && rightModel.name.Contains("Create") && - leftModel.name.Contains("On") && rightModel.name.Contains("On") && - leftModel.GetIl2CppType().Name == rightModel.GetIl2CppType().Name) - { - return true; - } - - if (leftModel.IsType() && rightModel.IsType()) + + if (first.IsType(out var firstProjectile) && second.IsType(out var secondProjectile)) { - var leftProjectile = leftModel.Cast(); - var rightProjectile = rightModel.Cast(); - return leftProjectile.id == rightProjectile.id || array; + return firstProjectile.id == secondProjectile.id; } - - if (leftModel.IsType(out var leftAttack) && - rightModel.IsType(out var rightAttack)) + + if (first.IsType(out var firstAttack) && second.IsType(out var secondAttack)) { - var lineLeft = leftAttack.weapons.Any(weapon => weapon.emission.IsType()); - var line = rightAttack.weapons.Any(weapon => weapon.emission.IsType()); - if (line != lineLeft) - { - return false; - } - - if (leftAttack.HasBehavior() != rightAttack.HasBehavior()) - { - return false; - } - - var leftDisplay = leftAttack.GetBehavior(); - var rightDisplay = rightAttack.GetBehavior(); + var leftDisplay = firstAttack.GetBehavior(); + var rightDisplay = secondAttack.GetBehavior(); if (leftDisplay != null && rightDisplay != null) { if (leftDisplay.display != rightDisplay.display) @@ -757,123 +233,25 @@ public static bool ModelsAreTheSame(Model leftModel, Model rightModel, bool arra return false; } } - else if (!(leftDisplay == null && rightDisplay == null)) + else if (leftDisplay == null && rightDisplay == null) { - /*var ancestor = history.GetAncestor(); - var ancestorWeapon = ancestor.GetWeapon(); - if (ancestorWeapon != null) - { - var ancestorDisplay = ancestorWeapon.projectile.display; - var match = leftAttack.weapons[0].projectile.display == ancestorDisplay - || rightAttack.weapons[0].projectile.display == ancestorDisplay; - }*/ return false; } } - - return rightModel.name == leftModel.name && rightModel.GetIl2CppType().Name == leftModel.GetIl2CppType().Name; - } - - /*public static bool IsType(this Object objectBase) - { - return objectBase.GetIl2CppType().IsType(); - }*/ - - private static bool IsType(this Type typ) - { - var ty = Il2CppType.From(typeof(T)); - return ty.IsAssignableFrom(typ); - } - - public static Type Type(this MemberInfo memberInfo) - { - if (memberInfo.GetIl2CppType().IsType()) - { - return memberInfo.Cast().FieldType; - } - - if (memberInfo.GetIl2CppType().IsType()) - { - return memberInfo.Cast().PropertyType; - } - - return null; - } - - public static Object GetValue(this MemberInfo memberInfo, Object obj) - { - if (memberInfo.GetIl2CppType().IsType()) - { - return memberInfo.Cast().GetValue(obj); - } - - if (memberInfo.GetIl2CppType().IsType()) - { - return memberInfo.Cast().GetValue(obj); - } - - return null; - } - - public static void SetValue(this MemberInfo memberInfo, Object obj, Object newValue) - { - if (memberInfo.GetIl2CppType().IsType()) - { - memberInfo.Cast().SetValue(obj, newValue); - } - - if (memberInfo.GetIl2CppType().IsType()) - { - memberInfo.Cast().SetValue(obj, newValue, null); - } + + + return first.name == second.name && first.GetIl2CppType().FullName == second.GetIl2CppType().FullName; } - public class History + private static float Average(float? first, float? second) { - public readonly Stack left; - public readonly Stack right; - public readonly Stack ancestor; - - public int Depth; - - public History() - { - left = new Stack(); - right = new Stack(); - ancestor = new Stack(); - Depth = -1; - } - - public void Push(Object l, Object r, Object a) - { - left.Push(l); - right.Push(r); - ancestor.Push(a); - Depth++; - } - - public Object Pop() - { - var pop = left.Pop(); - right.Pop(); - ancestor.Pop(); - Depth--; - return pop; - } - - public T GetLeft() where T : Object - { - return (from o in left where o.IsType() select o.Cast()).FirstOrDefault(); - } - - public T GetRight() where T : Object - { - return (from o in right where o.IsType() select o.Cast()).FirstOrDefault(); - } - - public T GetAncestor() where T : Object - { - return (from o in ancestor where o.IsType() select o.Cast()).FirstOrDefault(); - } + if (first is null && second is not null) + return second.Value; + if (first is not null && second is null) + return first.Value; + if (first is null && second is null) + return 0; + + return (first!.Value + second!.Value) / 2; } -} +} \ No newline at end of file diff --git a/Merging/MergeFixes/FixAbilities.cs b/Merging/MergeFixes/FixAbilities.cs index 1a7427c..546d7a4 100644 --- a/Merging/MergeFixes/FixAbilities.cs +++ b/Merging/MergeFixes/FixAbilities.cs @@ -4,17 +4,17 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixAbilities : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - foreach (var ability in model.GetAbilities().Where(abilityModel => abilityModel.displayName is "Supply Drop" or "Bomb Blitz")) + foreach (var ability in tower.GetAbilities().Where(abilityModel => abilityModel.displayName is "Supply Drop" or "Bomb Blitz")) { var activateAttackModel = ability.GetBehavior(); activateAttackModel.isOneShot = true; } - if (model.appliedUpgrades.Contains(UpgradeType.EliteSniper)) + if (tower.appliedUpgrades.Contains(UpgradeType.EliteSniper)) { - model.RemoveBehavior(); + tower.RemoveBehavior(); } } } diff --git a/Merging/MergeFixes/FixAdoraSacrifice.cs b/Merging/MergeFixes/FixAdoraSacrifice.cs index 6acdd16..3a0eb87 100644 --- a/Merging/MergeFixes/FixAdoraSacrifice.cs +++ b/Merging/MergeFixes/FixAdoraSacrifice.cs @@ -2,11 +2,11 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixAdoraSacrifice : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - foreach(var ability in model.GetAbilities().Where(abilityModel => abilityModel.displayName == "Blood Sacrifice")) + foreach(var ability in tower.GetAbilities().Where(abilityModel => abilityModel.displayName == "Blood Sacrifice")) { - model.RemoveBehavior(ability); + tower.RemoveBehavior(ability); } } } \ No newline at end of file diff --git a/Merging/MergeFixes/FixAdvancedIntel.cs b/Merging/MergeFixes/FixAdvancedIntel.cs index ff68535..cae7491 100644 --- a/Merging/MergeFixes/FixAdvancedIntel.cs +++ b/Merging/MergeFixes/FixAdvancedIntel.cs @@ -4,14 +4,14 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixAdvancedIntel : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.AdvancedIntel)) + //if (tower.appliedUpgrades.Contains(UpgradeType.AdvancedIntel)) { - model.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); - model.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); - model.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); - model.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); + tower.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); + tower.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); + tower.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); + tower.GetDescendants().ForEach(m => m.isSharedRangeEnabled = true); } } } diff --git a/Merging/MergeFixes/FixAirUnits.cs b/Merging/MergeFixes/FixAirUnits.cs deleted file mode 100644 index f92edbb..0000000 --- a/Merging/MergeFixes/FixAirUnits.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack.Behaviors; -using Il2CppAssets.Scripts.Models.Towers.Weapons.Behaviors; - -namespace OmegaCrosspathing.MergeFixes; - -public class FixAirUnits : PostMergeFix -{ - public override void Apply(TowerModel model) - { - try - { - if (!model.HasBehavior(out var airunit)) - return; - - model.towerSelectionMenuThemeId = "HeliPilot"; - - var airunits = model.GetBehaviors(); - - if (airunits.Count > 1) - { - Algorithm.DeepMerge(airunit, airunits[1], new Algorithm.History()); - model.RemoveBehavior(airunits[1]); - } - - foreach (var attackModel in model.GetAttackModels().Where(x=>x.HasBehavior())) - { - foreach (var weaponModel in attackModel.weapons) - { - if (!weaponModel.HasBehavior()) continue; - MelonLogger.Msg("Fixing FireFromAirUnitModel for " + model.name); - - if (model.HasBehavior(out var attackAirUnitModel)) - { - attackAirUnitModel.AddBehavior(weaponModel); - } - - if (attackModel.HasBehavior()) - { - var followTouchSettingModel = attackModel.GetBehavior(); - followTouchSettingModel.isSelectable = false; - } - - attackModel.RemoveBehavior(); - - attackModel.RemoveBehavior(); - - if (attackModel.HasBehavior()) - { - var pursuitSettingModel = attackModel.GetBehavior(); - pursuitSettingModel.isSelectable = false; - if (attackModel.HasBehavior()) - { - attackModel.RemoveBehavior(); - } - } - if (attackModel.HasBehavior()) - { - var pursuitSettingModel = attackModel.GetBehavior(); - pursuitSettingModel.isSelectable = false; - attackModel.RemoveBehavior(); - attackModel.RemoveBehavior(); - } - - attackModel.RemoveBehavior(weaponModel); - } - } - - if (!airunit.HasBehavior()) - { - MelonLogger.Msg("No HeliMovementModel for " + model.name); - foreach (var behavior in airunit.behaviors) - { - MelonLogger.Msg(behavior.name); - } - foreach (var behavior in model.behaviors) - { - MelonLogger.Msg(behavior.name); - } - return; - } - - MelonLogger.Msg("Fixing AirUnitModel for " + model.name); - - airunit.RemoveBehavior(); - airunit.RemoveBehavior(); - airunit.RemoveBehavior(); - - - - foreach (var airattack in model.GetBehaviors()) - { - airattack.RemoveBehavior(); - airattack.RemoveBehaviors(); - airattack.RemoveBehavior(); - airattack.RemoveBehavior(); - } - - model.UpdateTargetProviders(); - } - catch (System.Exception e) - { - MelonLogger.Error(e); - } - } -} diff --git a/Merging/MergeFixes/FixAircraftCarriers.cs b/Merging/MergeFixes/FixAircraftCarriers.cs index 8fbe22c..2c2c029 100644 --- a/Merging/MergeFixes/FixAircraftCarriers.cs +++ b/Merging/MergeFixes/FixAircraftCarriers.cs @@ -1,9 +1,4 @@ -using Il2CppAssets.Scripts.Models.GenericBehaviors; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack.Behaviors; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Emissions; -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Emissions.Behaviors; -using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; +using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; using Il2CppAssets.Scripts.Models.Towers.Weapons; using Il2CppAssets.Scripts.Models.Towers.Weapons.Behaviors; @@ -11,17 +6,11 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixAircraftCarriers : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.AircraftCarrier)) + if (tower.appliedUpgrades.Contains(UpgradeType.AircraftCarrier)) { - if (model.appliedUpgrades.Contains(UpgradeType.MonkeyPirates)) - { - foreach (var ability in model.GetAbilities().Where(x=>x.displayName == "MOAB Takedown")) - ability.GetDescendant().RemoveBehavior(); - } - - model.GetDescendants().ForEach(weaponModel => + tower.GetDescendants().ForEach(weaponModel => { var createTowerModel = weaponModel.GetDescendant(); var filter = weaponModel.GetDescendant(); @@ -31,54 +20,6 @@ public override void Apply(TowerModel model) filter.baseSubTowerIds = new[] {filter.baseSubTowerId}; } }); - - model.GetAttackModels().ForEach(attackModel => - { - attackModel.GetDescendants() - .ForEach(targetModel => targetModel.rotateTower = false); - - attackModel.GetDescendants().ForEach(emissionModel => - { - if (emissionModel.behaviors == null) - { - return; - } - - var behaviors = emissionModel.behaviors.ToList(); - - foreach (var emission in emissionModel.behaviors - .GetItemsOfType()) - { - behaviors.RemoveAll(behaviorModel => behaviorModel.name == emission.name); - emissionModel.RemoveChildDependant(emission); - var behavior = new EmissionRotationOffDisplayModel("EmissionRotationOffDisplayModel_", - emission.offsetRotation); - behaviors.Add(behavior); - emissionModel.AddChildDependant(behavior); - } - - foreach (var emission in emissionModel.behaviors - .GetItemsOfType()) - { - behaviors.RemoveAll(behaviorModel => behaviorModel.name == emission.name); - emissionModel.RemoveChildDependant(emission); - var behavior = - new EmissionArcRotationOffDisplayDirectionModel( - "EmissionArcRotationOffDisplayDirectionModel_", emission.offsetRotation); - behaviors.Add(behavior); - emissionModel.AddChildDependant(behavior); - } - - emissionModel.behaviors = behaviors.ToIl2CppReferenceArray(); - }); - - if (!attackModel.HasBehavior()) - { - attackModel.AddBehavior(new DisplayModel("DisplayModel_AttackDisplay", - CreatePrefabReference(""), 0, DisplayCategory.Default)); - } - }); } } } \ No newline at end of file diff --git a/Merging/MergeFixes/FixAutoCollectings.cs b/Merging/MergeFixes/FixAutoCollectings.cs index 1b5fa2c..266e675 100644 --- a/Merging/MergeFixes/FixAutoCollectings.cs +++ b/Merging/MergeFixes/FixAutoCollectings.cs @@ -2,11 +2,11 @@ public class FixAutoCollectings : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.BananaSalvage)) + if (tower.appliedUpgrades.Contains(UpgradeType.BananaSalvage)) { - model.GetDescendants().ForEach(bankModel => { bankModel.autoCollect = true; }); + tower.GetDescendants().ForEach(bankModel => { bankModel.autoCollect = true; }); } } } diff --git a/Merging/MergeFixes/FixBananas.cs b/Merging/MergeFixes/FixBananas.cs deleted file mode 100644 index 48fa9d5..0000000 --- a/Merging/MergeFixes/FixBananas.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; - -namespace OmegaCrosspathing.Merging.MergeFixes; - -public class FixBananas : PostMergeFix -{ - public override void Apply(TowerModel model) - { - if (model.appliedUpgrades.Contains(UpgradeType.Marketplace) || - model.appliedUpgrades.Contains(UpgradeType.MonkeyBank)) // TODO smartly leave this out in MergeArray - { - model.GetWeapon().projectile.RemoveBehaviors(); - model.GetWeapon().projectile.RemoveBehaviors(); - model.GetWeapon().projectile.RemoveBehaviors(); - if (model.GetWeapon().projectile.GetBehavior() is AgeModel ageModel) - { - ageModel.Lifespan = 0; - } - - if (model.GetDescendant() is CreateTextEffectModel createTextEffectModel) - { - createTextEffectModel.useTowerPosition = true; - } - } - } -} diff --git a/Merging/MergeFixes/FixBehaviorNames.cs b/Merging/MergeFixes/FixBehaviorNames.cs index 4746f62..a872906 100644 --- a/Merging/MergeFixes/FixBehaviorNames.cs +++ b/Merging/MergeFixes/FixBehaviorNames.cs @@ -2,9 +2,9 @@ public class FixBehaviorNames : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - var behaviors = model.behaviors.ToList(); + var behaviors = tower.behaviors.ToList(); for (var i = 0; i < behaviors.Count; i++) { var behavior = behaviors[i]; diff --git a/Merging/MergeFixes/FixCamo.cs b/Merging/MergeFixes/FixCamo.cs index 1ff0c08..f529394 100644 --- a/Merging/MergeFixes/FixCamo.cs +++ b/Merging/MergeFixes/FixCamo.cs @@ -1,31 +1,36 @@ using Il2CppAssets.Scripts.Models.Towers.Filters; using Il2CppAssets.Scripts.Models.Towers.Projectiles; +using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; namespace OmegaCrosspathing.Merging.MergeFixes; public class FixCamo : PostMergeFix { - public override void Apply(TowerModel model, TowerModel second) + public static void SetHitCamo(ProjectileModel projectileModel) { - if (model.GetDescendants().Any(p => p.CanHitCamo()) || - model.GetDescendants().Any(x => !x.isActive) || model.GetAttackModels().Any(x => + if (projectileModel.HasBehavior(out var projectileFilterModel) && projectileFilterModel.filters.GetItemOfType() is { } filterInvisibleModel) + { + filterInvisibleModel.isActive = false; + } + } + public override void Apply(TowerModel tower, TowerModel second) + { + if (tower.GetDescendants().Any(p => p.CanHitCamo()) || + tower.GetDescendants().Any(x => !x.isActive) || tower.GetAttackModels().Any(x => x.GetDescendant() == null || !x.GetDescendant().isActive)) { - foreach (var projectile in model.GetDescendants().ToList() - .Where(x => x is not null)) + foreach (var projectile in tower.GetDescendants().ToList().Where(x => x is not null)) { - projectile?.SetHitCamo(true); + SetHitCamo(projectile); } - foreach (var filterInvisibleModel in model.GetDescendants().ToList() - .Where(x => x is not null)) + foreach (var filterInvisibleModel in tower.GetDescendants().ToList().Where(x => x is not null)) { filterInvisibleModel.isActive = false; } - foreach (var attackModel in model.GetAttackModels() - .Where(attackModel => attackModel.GetDescendant() != null)) + foreach (var attackModel in tower.GetAttackModels().Where(attackModel => attackModel.GetDescendant() != null)) { attackModel.GetDescendant().isActive = false; } @@ -36,19 +41,18 @@ public override void Apply(TowerModel model, TowerModel second) x.GetDescendant() == null || !x.GetDescendant().isActive)) { - foreach (var projectile in model.GetDescendants().ToList() - .Where(x => x is not null)) + foreach (var projectile in tower.GetDescendants().ToList().Where(x => x is not null)) { - projectile?.SetHitCamo(true); + SetHitCamo(projectile); } - foreach (var filterInvisibleModel in model.GetDescendants().ToList() + foreach (var filterInvisibleModel in tower.GetDescendants().ToList() .Where(x => x is not null)) { filterInvisibleModel.isActive = false; } - foreach (var attackModel in model.GetAttackModels() + foreach (var attackModel in tower.GetAttackModels() .Where(attackModel => attackModel.GetDescendant() != null)) { attackModel.GetDescendant().isActive = false; diff --git a/Merging/MergeFixes/FixCannonShips.cs b/Merging/MergeFixes/FixCannonShips.cs index abe8861..3f4e4ed 100644 --- a/Merging/MergeFixes/FixCannonShips.cs +++ b/Merging/MergeFixes/FixCannonShips.cs @@ -2,21 +2,14 @@ public class FixCannonShips : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.CannonShip)) + if (tower.appliedUpgrades.Contains(UpgradeType.CannonShip)) { - if (model.appliedUpgrades.Contains(UpgradeType.AircraftCarrier)) + if (tower.appliedUpgrades.Contains(UpgradeType.Destroyer)) // TODO apply rate buffs to all weapons { - { - //TODO fix the attack angles without crashing - } - } - - if (model.appliedUpgrades.Contains(UpgradeType.Destroyer)) // TODO apply rate buffs to all weapons - { - model.GetWeapon(4).Rate /= 5f; - model.GetWeapon(5).Rate /= 5f; + tower.GetWeapon(4).Rate /= 5f; + tower.GetWeapon(5).Rate /= 5f; } } } diff --git a/Merging/MergeFixes/FixClusterMauling.cs b/Merging/MergeFixes/FixClusterMauling.cs index 4c411f7..51e2530 100644 --- a/Merging/MergeFixes/FixClusterMauling.cs +++ b/Merging/MergeFixes/FixClusterMauling.cs @@ -5,15 +5,15 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixClusterMauling : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.MOABMauler)) + if (tower.appliedUpgrades.Contains(UpgradeType.MOABMauler)) { - var damageModifierForTagModels = model.GetDescendants().ToList(); + var damageModifierForTagModels = tower.GetDescendants().ToList(); var moabage = damageModifierForTagModels.FirstOrDefault(m => m.tag == "Moabs"); var ceramage = damageModifierForTagModels.FirstOrDefault(m => m.tag == "Ceramic"); - foreach (var projectileModel in model.GetDescendants().ToList() + foreach (var projectileModel in tower.GetDescendants().ToList() .Where(p => p.id == "Explosion")) { projectileModel.RemoveBehaviors(); diff --git a/Merging/MergeFixes/FixGlueOverriding.cs b/Merging/MergeFixes/FixGlueOverriding.cs index 6e605c8..52ddefe 100644 --- a/Merging/MergeFixes/FixGlueOverriding.cs +++ b/Merging/MergeFixes/FixGlueOverriding.cs @@ -8,11 +8,11 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixGlueOverriding : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.MOABGlue)) + if (tower.appliedUpgrades.Contains(UpgradeType.MOABGlue)) { - model.GetDescendants().ForEach(projectileModel => + tower.GetDescendants().ForEach(projectileModel => { var behaviors = projectileModel.behaviors.ToList(); behaviors.RemoveAll(m => m.name == "SlowModifierForTagModel_"); @@ -20,25 +20,25 @@ public override void Apply(TowerModel model) }); var lifeSpan = 0f; - model.GetDescendants().ForEach(m => { lifeSpan = Math.Max(lifeSpan, m.Lifespan); }); - model.GetDescendants().ForEach(m => { lifeSpan = Math.Max(lifeSpan, m.Lifespan); }); - model.GetDescendants().ForEach(m => + tower.GetDescendants().ForEach(m => { lifeSpan = Math.Max(lifeSpan, m.Lifespan); }); + tower.GetDescendants().ForEach(m => { lifeSpan = Math.Max(lifeSpan, m.Lifespan); }); + tower.GetDescendants().ForEach(m => { lifeSpan = Math.Max(lifeSpan, m.lifespan); }); - model.GetDescendants().ForEach(m => { m.Lifespan = lifeSpan; }); - model.GetDescendants().ForEach(m => { m.Lifespan = lifeSpan; }); - model.GetDescendants().ForEach(m => { m.lifespan = lifeSpan; }); + tower.GetDescendants().ForEach(m => { m.Lifespan = lifeSpan; }); + tower.GetDescendants().ForEach(m => { m.Lifespan = lifeSpan; }); + tower.GetDescendants().ForEach(m => { m.lifespan = lifeSpan; }); - model.GetDescendants().ForEach(filterModel => + tower.GetDescendants().ForEach(filterModel => { var models = filterModel.filters.ToList(); models.RemoveAll(m => m.IsType()); filterModel.filters = models.ToIl2CppReferenceArray(); }); - model.GetDescendants().ForEach(filterModel => + tower.GetDescendants().ForEach(filterModel => { var models = filterModel.filters.ToList(); models.RemoveAll(m => m.IsType()); diff --git a/Merging/MergeFixes/FixHeroVoicelines.cs b/Merging/MergeFixes/FixHeroVoicelines.cs new file mode 100644 index 0000000..da31f8e --- /dev/null +++ b/Merging/MergeFixes/FixHeroVoicelines.cs @@ -0,0 +1,14 @@ +namespace OmegaCrosspathing.Merging.MergeFixes; + +public class FixHeroVoicelines : PostMergeFix +{ + public override void Apply(TowerModel model) + { + model.RemoveBehaviors(); + model.RemoveBehaviors(); + model.RemoveBehaviors(); + model.RemoveBehaviors(); + model.RemoveBehaviors(); + model.RemoveBehaviors(); + } +} \ No newline at end of file diff --git a/Merging/MergeFixes/FixHeroes.cs b/Merging/MergeFixes/FixHeroes.cs index 005c9a4..39bb4dd 100644 --- a/Merging/MergeFixes/FixHeroes.cs +++ b/Merging/MergeFixes/FixHeroes.cs @@ -2,21 +2,21 @@ public class FixHeroes : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - foreach (var heroModel in model.GetBehaviors()) + foreach (var heroModel in tower.GetBehaviors()) { - model.RemoveBehavior(heroModel); + tower.RemoveBehavior(heroModel); } - foreach (var heroXpPerRoundModel in model.GetBehaviors()) + foreach (var heroXpPerRoundModel in tower.GetBehaviors()) { - model.RemoveBehavior(heroXpPerRoundModel); + tower.RemoveBehavior(heroXpPerRoundModel); } - foreach (var churchillBaseRotationModel in model.GetBehaviors()) + foreach (var churchillBaseRotationModel in tower.GetBehaviors()) { - model.RemoveBehavior(churchillBaseRotationModel); + tower.RemoveBehavior(churchillBaseRotationModel); } } } \ No newline at end of file diff --git a/Merging/MergeFixes/FixHomingProjectiles.cs b/Merging/MergeFixes/FixHomingProjectiles.cs index ee24834..ca0c2d8 100644 --- a/Merging/MergeFixes/FixHomingProjectiles.cs +++ b/Merging/MergeFixes/FixHomingProjectiles.cs @@ -5,9 +5,9 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixHomingProjectiles : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - foreach (var projectileModel in model.GetDescendants().ToList().Where(projectileModel => projectileModel.GetBehavior() != null)) + foreach (var projectileModel in tower.GetDescendants().ToList().Where(projectileModel => projectileModel.GetBehavior() != null)) { projectileModel.RemoveBehavior(); } diff --git a/Merging/MergeFixes/FixIceMonkeyRange.cs b/Merging/MergeFixes/FixIceMonkeyRange.cs index 1e42431..e4576f0 100644 --- a/Merging/MergeFixes/FixIceMonkeyRange.cs +++ b/Merging/MergeFixes/FixIceMonkeyRange.cs @@ -2,11 +2,11 @@ public class FixIceMonkeyRange : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.GetDescendant().IsType(out var slow)) + foreach (var slow in tower.GetDescendants().ToList()) { - slow.zoneRadius = model.range + 5; + slow.zoneRadius = tower.range + 5; } } } diff --git a/Merging/MergeFixes/FixLifespans.cs b/Merging/MergeFixes/FixLifespans.cs index af385d6..e900114 100644 --- a/Merging/MergeFixes/FixLifespans.cs +++ b/Merging/MergeFixes/FixLifespans.cs @@ -4,11 +4,12 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixLifespans : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - model.GetDescendants().ForEach(ageModel => + tower.GetDescendants().ForEach(ageModel => { ageModel.Lifespan = System.Math.Max(ageModel.Lifespan, ageModel.lifespanFrames / 60f); + ageModel.lifespan = System.Math.Max(ageModel.Lifespan, ageModel.lifespanFrames / 60f); }); } } diff --git a/Merging/MergeFixes/FixPlasmaBeams.cs b/Merging/MergeFixes/FixPlasmaBeams.cs index e7da2e7..55cbf28 100644 --- a/Merging/MergeFixes/FixPlasmaBeams.cs +++ b/Merging/MergeFixes/FixPlasmaBeams.cs @@ -5,26 +5,26 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixPlasmaBeams : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.PlasmaAccelerator)) + if (tower.appliedUpgrades.Contains(UpgradeType.PlasmaAccelerator)) { - model.GetWeapon().projectile.radius = 2; + tower.GetWeapon().projectile.radius = 2; //model.GetWeapon().projectile.RemoveBehavior(); //model.GetWeapon().projectile.RemoveBehavior(); } - var lineProjectileAttacks = model.GetAttackModels().Where(attackModel => + var lineProjectileAttacks = tower.GetAttackModels().Where(attackModel => attackModel.weapons.Any(weaponModel => weaponModel.emission.IsType())).ToList(); if (lineProjectileAttacks.Count > 1) { - var behaviors = Enumerable.ToList(model.behaviors); + var behaviors = Enumerable.ToList(tower.behaviors); behaviors.RemoveAll(m => m.IsType(out var attackModel) && attackModel.weapons.Any(weaponModel => weaponModel.emission.IsType())); behaviors.Add(lineProjectileAttacks[0]); - model.behaviors = behaviors.ToIl2CppReferenceArray(); + tower.behaviors = behaviors.ToIl2CppReferenceArray(); } } } diff --git a/Merging/MergeFixes/FixRoboMonkeys.cs b/Merging/MergeFixes/FixRoboMonkeys.cs new file mode 100644 index 0000000..ad7850e --- /dev/null +++ b/Merging/MergeFixes/FixRoboMonkeys.cs @@ -0,0 +1,45 @@ +using BTD_Mod_Helper.Api; +using Il2CppAssets.Scripts.Models.GenericBehaviors; +using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack.Behaviors; +using Il2CppAssets.Scripts.Simulation.SMath; + +namespace OmegaCrosspathing.Merging.MergeFixes; + +public class FixRoboMonkeys : PostMergeFix +{ + public override void Apply(TowerModel tower) + { + if(tower.appliedUpgrades.Contains(UpgradeType.RoboMonkey)) + { + foreach (var attackModel in tower.GetAttackModels().Where(x => x.HasBehavior())) + { + attackModel.RemoveBehavior(); + + var newAttackModel = attackModel.Duplicate(); + + foreach (var weapon in newAttackModel.weapons) + { + weapon.ejectX *= -1; + } + + var displayModel = newAttackModel.GetBehavior(); + + if (displayModel.display.guidRef == "b86ee66981bfcc14b964b9731264cddf") + { + displayModel.display = CreatePrefabReference("63df1a60aed70cc49acadb98e3190bf3"); + } + + if (displayModel.display.guidRef == "c7974835e6380b741b18d9282e249fe5") + { + displayModel.display = CreatePrefabReference("c8384b47962cb5547b85f0a0e4fba047"); + } + + if (displayModel.display.guidRef == "8a151c6c111ff5641882e51afc28c740") + displayModel.display = CreatePrefabReference("fdff998beaa71ee45977df86cfda6d96"); + + + tower.AddBehavior(newAttackModel); + } + } + } +} \ No newline at end of file diff --git a/Merging/MergeFixes/FixSmallRanges.cs b/Merging/MergeFixes/FixSmallRanges.cs index 60039e8..86fc60e 100644 --- a/Merging/MergeFixes/FixSmallRanges.cs +++ b/Merging/MergeFixes/FixSmallRanges.cs @@ -1,14 +1,17 @@ -namespace OmegaCrosspathing.Merging.MergeFixes; +using System; +using Il2CppAssets.Scripts.Models.Towers.Behaviors.Attack; +using System.Linq; + +namespace OmegaCrosspathing.Merging.MergeFixes; public class FixSmallRanges : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { // TODO: are there any cases where this shouldn't be the case? - var attackModels = model.GetAttackModels(); - foreach (var attackModel in attackModels.Where(attackModel => attackModel.range < model.range)) + foreach (var attackModel in tower.GetDescendants().ToList()) { - attackModel.range = model.range; + attackModel.range = Math.Max(attackModel.range, tower.range); } } } diff --git a/Merging/MergeFixes/FixSpectre.cs b/Merging/MergeFixes/FixSpectre.cs index aae3678..6b5f4f4 100644 --- a/Merging/MergeFixes/FixSpectre.cs +++ b/Merging/MergeFixes/FixSpectre.cs @@ -5,12 +5,12 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixSpectre : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.NevaMissTargeting)) + if (tower.appliedUpgrades.Contains(UpgradeType.NevaMissTargeting)) { - var trackTargetModel = model.GetDescendant(); - model.GetAttackModels().ForEach(attackModel => + var trackTargetModel = tower.GetDescendant(); + tower.GetAttackModels().ForEach(attackModel => { attackModel.GetDescendants().ForEach(projectileModel => { diff --git a/Merging/MergeFixes/FixSpikeStorm.cs b/Merging/MergeFixes/FixSpikeStorm.cs deleted file mode 100644 index 872ce6f..0000000 --- a/Merging/MergeFixes/FixSpikeStorm.cs +++ /dev/null @@ -1,26 +0,0 @@ -using Il2CppAssets.Scripts.Models.Towers.Behaviors.Abilities.Behaviors; -using Il2CppAssets.Scripts.Models.Towers.Projectiles.Behaviors; - -namespace OmegaCrosspathing.Merging.MergeFixes; - -public class FixSpikeStorm : PostMergeFix -{ - public override void Apply(TowerModel model) - { - if (model.appliedUpgrades.Contains(UpgradeType.SpikeStorm)) - { - var realProjectile = model.GetWeapon().projectile; - model.GetAbility().GetBehavior().attacks.ForEach(attackModel => - { - var projectileModel = attackModel.weapons[0].projectile; - var ageRandomModel = projectileModel.GetBehavior().Duplicate(); - - var newProjectile = realProjectile.Duplicate(); - newProjectile.RemoveBehaviors(); - newProjectile.AddBehavior(ageRandomModel); - - attackModel.weapons[0].projectile = newProjectile; - }); - } - } -} diff --git a/Merging/MergeFixes/FixTemples.cs b/Merging/MergeFixes/FixTemples.cs index 30eebd6..46b8790 100644 --- a/Merging/MergeFixes/FixTemples.cs +++ b/Merging/MergeFixes/FixTemples.cs @@ -4,18 +4,17 @@ namespace OmegaCrosspathing.Merging.MergeFixes; public class FixTemples : PostMergeFix { - public override void Apply(TowerModel model) + public override void Apply(TowerModel tower) { - if (model.appliedUpgrades.Contains(UpgradeType.SunTemple)) + if (tower.appliedUpgrades.Contains(UpgradeType.SunTemple)) { - foreach (var attackModel in model.GetAttackModels()) + foreach (var attackModel in tower.GetAttackModels()) { - var rotateToTargetModel = attackModel.GetBehavior(); - if (rotateToTargetModel != null) + if (attackModel.HasBehavior()) { - rotateToTargetModel.rotateTower = false; + attackModel.GetBehavior().rotateTower = false; } - + attackModel.RemoveBehaviors(); } } diff --git a/Merging/MergeFixes/PostMergeFix.cs b/Merging/MergeFixes/PostMergeFix.cs index ac04c7f..562ec4a 100644 --- a/Merging/MergeFixes/PostMergeFix.cs +++ b/Merging/MergeFixes/PostMergeFix.cs @@ -7,11 +7,10 @@ public abstract class PostMergeFix : ModContent public override int RegisterPerFrame => 999; public sealed override void Register(){} - public virtual void Apply(TowerModel model) + public virtual void Apply(TowerModel tower) { } - - public virtual void Apply(TowerModel model, TowerModel second) + public virtual void Apply(TowerModel first, TowerModel second) { } } diff --git a/Merging/SimulationFixes/AnotherAirUnitModelFix.cs b/Merging/SimulationFixes/AnotherAirUnitModelFix.cs deleted file mode 100644 index 754ff9d..0000000 --- a/Merging/SimulationFixes/AnotherAirUnitModelFix.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Il2CppAssets.Scripts.Simulation.Towers.Behaviors; -using Il2CppAssets.Scripts.Unity.Bridge; - -namespace OmegaCrosspathing.SimulationFixes; - -public class AnotherAirUnitModelFix : SimulationFix -{ - public override void Apply(TowerToSimulation tts) - { - if (tts.tower.HasTowerBehavior()) - { - var airUnit = tts.tower.GetTowerBehavior(); - //airUnit.modelBehaviors.GetItemOfType(); - } - } -} diff --git a/Merging/SimulationFixes/SimulationFix.cs b/Merging/SimulationFixes/SimulationFix.cs index 07961e8..4c42054 100644 --- a/Merging/SimulationFixes/SimulationFix.cs +++ b/Merging/SimulationFixes/SimulationFix.cs @@ -1,11 +1,11 @@ using BTD_Mod_Helper.Api; using Il2CppAssets.Scripts.Unity.Bridge; -namespace OmegaCrosspathing.SimulationFixes; +namespace OmegaCrosspathing.Merging.SimulationFixes; public abstract class SimulationFix : ModContent { public override int RegisterPerFrame => 999; public sealed override void Register(){} - public abstract void Apply(TowerToSimulation tts); + public abstract void Apply(TowerToSimulation tts, TowerModel tower, TowerModel newTower); } diff --git a/ModHelperData.cs b/ModHelperData.cs index bee86b9..56f2f90 100644 --- a/ModHelperData.cs +++ b/ModHelperData.cs @@ -3,8 +3,8 @@ public static class ModHelperData { public const string Name = "OmegaCrosspathing"; - public const string Description = "Allows you to merge towers together, should be fully compatible with ultimate crosspathing, custom towers, custom heroes, and custom towersets. Thanks to doombubbles for the ultimate crosspathing algorithm, which was used here."; - public const string Version = "0.0.3"; + public const string Description = "Allows you to merge towers together, should be fully compatible with ultimate crosspathing, custom towers, custom heroes, and custom towersets."; + public const string Version = "0.0.4"; public const string RepoOwner = "GrahamKracker"; public const string RepoName = "OmegaCrosspathing"; public const string WorksOnVersion = "37"; diff --git a/ModelBehaviorExt.cs b/ModelBehaviorExt.cs deleted file mode 100644 index 5f28270..0000000 --- a/ModelBehaviorExt.cs +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/OmegaCrosspathing.csproj b/OmegaCrosspathing.csproj index 0ae33f2..e149de3 100644 --- a/OmegaCrosspathing.csproj +++ b/OmegaCrosspathing.csproj @@ -14,20 +14,17 @@ true none + - - - - - - + $(BloonsTD6)\Mods\PathsPlusPlus.dll + diff --git a/Patches.cs b/Patches.cs index 48fc6a4..dc7b472 100644 --- a/Patches.cs +++ b/Patches.cs @@ -1,6 +1,7 @@ using System; using BTD_Mod_Helper.Api; using BTD_Mod_Helper.Api.Components; +using BTD_Mod_Helper.Api.Helpers; using Il2CppAssets.Scripts.Models; using Il2CppAssets.Scripts.Simulation.Objects; using Il2CppAssets.Scripts.Simulation.Towers; @@ -9,6 +10,8 @@ using Il2CppAssets.Scripts.Unity.UI_New.InGame.AbilitiesMenu; using Il2CppAssets.Scripts.Unity.UI_New.InGame.TowerSelectionMenu; using OmegaCrosspathing.Merging; +using OmegaCrosspathing.Merging.SimulationFixes; +using PathsPlusPlus; using UnityEngine; using static OmegaCrosspathing.UI; @@ -16,55 +19,108 @@ namespace OmegaCrosspathing; public partial class Main { + private static bool OCUIenabled = true; + [HarmonyPatch(typeof(TowerSelectionMenu), nameof(TowerSelectionMenu.Show))] + [HarmonyPatch(typeof(TowerSelectionMenu), nameof(TowerSelectionMenu.UpdateTower))] + [HarmonyPatch(typeof(TowerSelectionMenu), nameof(TowerSelectionMenu.UpdateAbilities))] [HarmonyPostfix] public static void TowerSelectionMenu_Show(TowerSelectionMenu __instance) { - if (__instance.selectedTower is null) - { - return; - } + if (__instance.selectedTower is null) return; - TaskScheduler.ScheduleTask(() => //required for paths++ support + TaskScheduler.ScheduleTask(() => { + if (__instance.selectedTower is null) return; + + OCTogglePanel.gameObject.SetActive(true); + if (__instance.selectedTower.owner != InGame.instance.UnityToSimulation.MyPlayerNumber) { _mainpanel.gameObject.SetActive(false); + OCTogglePanel.gameObject.SetActive(false); return; } if (__instance.selectedTower.tower.towerModel.IsHero()) { _mainpanel.gameObject.SetActive(false); + OCTogglePanel.gameObject.SetActive(false); return; } if (__instance.selectedTower.tower.towerModel.isParagon) { _mainpanel.gameObject.SetActive(false); + OCTogglePanel.gameObject.SetActive(false); return; } - _mainpanel.gameObject.SetActive(true); - - for (var i = 0; i < TowerSelectionMenu.instance.towerDetails.transform.childCount; i++) + if (__instance.selectedTower.tower.towerModel.dontDisplayUpgrades || __instance.selectedTower.tower.towerModel.isSubTower || __instance.selectedTower.tower.towerModel.isPowerTower) { - TowerSelectionMenu.instance.towerDetails.transform.GetChild(i).gameObject.SetActive(false); + _mainpanel.gameObject.SetActive(false); + OCTogglePanel.gameObject.SetActive(false); } + UpdateVanillaUI(); }); } + private static void UpdateVanillaUI() + { + if (_mainpanel == null) return; + + _mainpanel.gameObject.SetActive(OCUIenabled); + + var count = TowerSelectionMenu.instance.upgradeButtons.Count; + if (count > 3) + { + count = 3; + } + + for (var index = 0; index < count; index++) + { + var upgradeObject = TowerSelectionMenu.instance.upgradeButtons[index]; + upgradeObject.gameObject.SetActive(!OCUIenabled); + } + + TowerSelectionMenu.instance.towerDetails.SetActive(!OCUIenabled); + } + [HarmonyPatch(typeof(TowerSelectionMenu), nameof(TowerSelectionMenu.Initialise))] [HarmonyPostfix] public static void TowerSelectionMenu_Initialise(TowerSelectionMenu __instance) { - //MelonLogger.Msg("TowerSelectionMenu_Initialise"); + for (var index = 0; index < Pathsliders.Length; index++) + { + Pathsliders[index] = null; + } + + Pathsplusplussliders.Clear(); + var rect = __instance.towerDetails.GetComponent().rect; + var parent = __instance.towerDetails.transform.parent; + OCTogglePanel = parent.parent.gameObject.AddModHelperPanel( + new Info("ToggleButtonPanel") + { + AnchorMin = new Vector2(.75f, .905f), + AnchorMax = new Vector2(.975f, .945f) + }, null, RectTransform.Axis.Horizontal, 10); + + OCTogglePanel.AddText(new Info("ToggleButtonLabel", 100), "OC:", 69); + + OCTogglePanel.AddCheckbox(new Info("ToggleButton", 80), OCUIenabled, VanillaSprites.BlueInsertPanelRound, + new Action(toggle => + { + OCUIenabled = toggle; + UpdateVanillaUI(); + })); + + _mainpanel = - __instance.towerDetails.transform.parent.gameObject.AddModHelperPanel(new Info("MergingPanel", + parent.gameObject.AddModHelperPanel(new Info("MergingPanel", InfoPreset.FillParent)); towersetselect = _mainpanel.AddScrollPanel(new Info("TowersetSelect", @@ -92,69 +148,80 @@ public static void TowerSelectionMenu_Initialise(TowerSelectionMenu __instance) cost.enabled = false; + mergebutton = finalselect.AddButton(new Info("MergeButton", 350, 200, new Vector2(.765f, .5f)), + VanillaSprites.GreenBtnLong, new Action(() => + { + if (InGame.instance.GetCash() < totalcost) return; + + var OCMutator = TowerSelectionMenu.instance.selectedTower.tower.GetMutator("OC") + ?.Cast(); - mergebutton = - finalselect.AddButton(new Info("MergeButton", 350, 200, new Vector2(.765f, .5f)), - VanillaSprites.GreenBtnLong, new Action(() => - { - if (InGame.instance.GetCash() < totalcost) - { - return; - } - var OCMutator = TowerSelectionMenu.instance.selectedTower.tower.GetMutator("OC") - ?.Cast(); + if (TowerSelectionMenu.instance.selectedTower.tower.mutators != null) + TowerSelectionMenu.instance.selectedTower.tower.RemoveMutatorsById("OC"); - if (TowerSelectionMenu.instance.selectedTower.tower.mutators != null) - TowerSelectionMenu.instance.selectedTower.tower.RemoveMutatorsById("OC"); + var savedata = selectedtower.GetBaseId() + ":" + selectedtower.tiers[0] + "-" + selectedtower.tiers[1] + + "-" + + selectedtower.tiers[2]; - var savedata = selectedtower.GetBaseId() + ":" + selectedtower.tiers[0] + "-" + selectedtower.tiers[1] + "-" + selectedtower.tiers[2]; + if (selectedtower.IsHero()) + savedata = "hero:" + selectedtower.GetBaseId() + ":" + selectedtower.tiers[0]; - if (selectedtower.IsHero()) + TowerSelectionMenu.instance.selectedTower.tower.AddMutator( + new SupportRemoveFilterOutTag.MutatorTower("OC", + OCMutator?.removeScriptsWithSupportMutatorId + savedata + ",", + null)); + + foreach(var simulationFix in ModContent.GetContent()) + { + try + { + simulationFix.Apply(TowerSelectionMenu.instance.selectedTower, TowerSelectionMenu.instance.selectedTower.tower.towerModel, selectedtower.Duplicate()); + } + catch (Exception e) { - savedata = "hero:" + selectedtower.GetBaseId() + ":" + selectedtower.tiers[0]; + MelonLogger.Error("Error during simulationfix: " + simulationFix.Name + ", but thanks to this message, the crisis has been averted :)"); + MelonLogger.Warning(e); } + } + if (Main.HasPathsPlusPlus) + { + ApplyPaths(); + } - TowerSelectionMenu.instance.selectedTower.tower.AddMutator( - new SupportRemoveFilterOutTag.MutatorTower("OC", - OCMutator?.removeScriptsWithSupportMutatorId + savedata + ",", - null)); + var owner = TowerSelectionMenu.instance.selectedTower.tower.owner; - var owner = TowerSelectionMenu.instance.selectedTower.tower.owner; + if (owner == -1) + owner = 0; + else + owner--; - if (owner == -1) - { - owner = 0; - } - else - { - owner--; - } + InGame.instance.GetCashManager(owner).cash.Value -= totalcost; + InGame.instance.bridge.OnCashChangedSim(); - InGame.instance.GetCashManager(owner).cash.Value -= totalcost; - InGame.instance.bridge.OnCashChangedSim(); + TowerSelectionMenu.instance.selectedTower.tower.worth += totalcost; - TowerSelectionMenu.instance.selectedTower.tower.worth += totalcost; + HideAllSelected(); + selectedtower = null; + foreach (var slider in Pathsliders) + slider.SetCurrentValue(0); + foreach (var slider in Pathsplusplussliders.Values) + slider.SetCurrentValue(0); - HideAllSelected(); - selectedtower = null; - foreach (var slider in Pathsliders) - slider.SetCurrentValue(0); - foreach (var slider in Pathsplusplussliders.Values) - slider.SetCurrentValue(0); - UpdateBottomBar(); + UpdateBottomBar(); - AbilityMenu.instance.AbilitiesChanged(); - AbilityMenu.instance.TowerChanged(TowerSelectionMenu.instance.selectedTower); - AbilityMenu.instance.Update(); + AbilityMenu.instance.AbilitiesChanged(); + AbilityMenu.instance.TowerChanged(TowerSelectionMenu.instance.selectedTower); + AbilityMenu.instance.Update(); - TowerSelectionMenu.instance.themeManager.UpdateTheme(TowerSelectionMenu.instance - .selectedTower); - TowerSelectionMenu.instance.UpdateTower(); - })); + TowerSelectionMenu.instance.themeManager.UpdateTheme(TowerSelectionMenu.instance.selectedTower); + TowerSelectionMenu.instance.UpdateTower(); + TowerSelectionMenu.instance.selectedTower.tower.Hilight(); + TowerSelectionMenu_Show(TowerSelectionMenu.instance); + })); mergetext = mergebutton.AddText(new Info("MergeText", buttonSize, buttonSize, new Vector2(.5f, .55f)), "Merge", @@ -176,17 +243,26 @@ public static void TowerSelectionMenu_Initialise(TowerSelectionMenu __instance) LockInputFields(); } + private static void ApplyPaths() + { + if (selectedtower == null) return; + if (!Main.HasPathsPlusPlus) return; + foreach (var path in ModContent.GetContent().Where(p => p.Tower == selectedtower.baseId)) + { + if (Pathsplusplussliders.All(p => p.Value.name.Split(':')[1] != path.Id)) continue; + TowerSelectionMenu.instance.selectedTower.tower.SetTier(path.Id, + (int)Pathsplusplussliders.First(p => p.Value.name.Split(':')[1] == path.Id).Value.CurrentValue); + } + } + [HarmonyPatch(typeof(SupportRemoveFilterOutTag.MutatorTower), nameof(SupportRemoveFilterOutTag.MutatorTower.Mutate))] [HarmonyPrefix] - static bool SupportRemoveFilterOutTag_MutatorTower_Mutate(SupportRemoveFilterOutTag.MutatorTower __instance, + private static bool SupportRemoveFilterOutTag_MutatorTower_Mutate(SupportRemoveFilterOutTag.MutatorTower __instance, Model model, ref bool __result) { - if (__instance.id != "OC") - { - return true; - } + if (__instance.id != "OC") return true; var tower = model.Cast(); @@ -198,23 +274,28 @@ static bool SupportRemoveFilterOutTag_MutatorTower_Mutate(SupportRemoveFilterOut { var nonheroid = id.Replace("hero:", ""); towerToMerge = InGame.instance.GetGameModel() - .GetTowerModel(nonheroid.Split(':')[0], int.Parse(nonheroid.Split(':')[1])); + .GetTowerModel(nonheroid.Split(':')[0], int.Parse(nonheroid.Split(':')[1])).Duplicate(); } else { var tiers = id.Split(':')[1]; towerToMerge = InGame.instance.GetGameModel().GetTowerModel(id.Split(':')[0], - int.Parse(tiers.Split('-')[0]), int.Parse(tiers.Split('-')[1]), int.Parse(tiers.Split('-')[2])); + int.Parse(tiers.Split('-')[0]), int.Parse(tiers.Split('-')[1]), int.Parse(tiers.Split('-')[2])) + .Duplicate(); } - Algorithm.Merge(tower, towerToMerge); + Algorithm.Merge(tower, towerToMerge); + //GameModelExporter.Export(tower, "selected_tower.json"); } __result = true; return false; } - - [HarmonyPatch(typeof(Tower), nameof(Tower.AddMutator))] + + [HarmonyPatch(typeof(Tower), nameof(Tower.AddMutator))] [HarmonyPrefix] - static bool Tower_AddMutator(Tower __instance, BehaviorMutator mutator)=> !(__instance.towerModel.isSubTower && mutator.id == "OC"); + private static bool Tower_AddMutator(Tower __instance, BehaviorMutator mutator) + { + return !(__instance.towerModel.isSubTower && mutator.id == "OC"); + } } \ No newline at end of file diff --git a/UI.cs b/UI.cs index ae14404..8fbf20f 100644 --- a/UI.cs +++ b/UI.cs @@ -37,6 +37,7 @@ public class UI public static ModHelperText invalidtext; public static ModHelperPanel levelselect; public static ModHelperSlider levelslider; + public static ModHelperPanel OCTogglePanel; public static readonly Dictionary> TowerButtonsBySet = new(); public static readonly Dictionary SelectedImages = new(); @@ -58,7 +59,7 @@ public static void SetUpLevelInput() _ => { Main.selectedtower = InGame.instance.GetGameModel() - .GetTowerModel(Main.selectedBaseID, (int)levelslider.CurrentValue); + .GetTowerModel(Main.selectedBaseID, (int)levelslider.CurrentValue).Duplicate(); UpdateBottomBar(); } )); @@ -84,7 +85,11 @@ public static void SetUpPathInput() { Main.selectedtower = InGame.instance.GetGameModel().GetTowerModel(Main.selectedBaseID, (int)Pathsliders[0].CurrentValue, (int)Pathsliders[1].CurrentValue, - (int)Pathsliders[2].CurrentValue); + (int)Pathsliders[2].CurrentValue)?.Duplicate(); + + if (Main.HasPathsPlusPlus) + ApplyPathsPlusPlusSliders(Main.selectedtower); + UpdateBottomBar(); } )); @@ -97,14 +102,16 @@ public static void SetUpPathInput() pathselect.ScrollRect.enabled = false; } - public static void ApplyPathPlusPlus(PathPlusPlus path, int tier, ref TowerModel tower) + public static void ApplyPathPlusPlus(PathPlusPlus path, int tier, TowerModel? tower) { - var list = tower.appliedUpgrades.ToList(); - foreach (var pathPlusPlus in GetContent().SelectMany(p=> p.Upgrades)) + if (!Main.HasPathsPlusPlus) + return; + + if (tower == null) { - list.RemoveAll(p => p == pathPlusPlus.Id); + return; } - tower.appliedUpgrades = list.ToArray(); + var list = tower.appliedUpgrades.ToList(); tower.tier = Math.Max(tower.tier, tier); for (var i = 0; i < tier; i++) @@ -117,11 +124,13 @@ public static void ApplyPathPlusPlus(PathPlusPlus path, int tier, ref TowerModel tower.portrait = upgrade.PortraitReference; } - if (!tower.appliedUpgrades.Contains(upgrade.Id)) + if (!list.Contains(upgrade.Id)) { - tower.appliedUpgrades = tower.appliedUpgrades.AddTo(upgrade.Id); + list.Add(upgrade.Id); } - } + } + + tower.appliedUpgrades = list.ToArray(); } @@ -159,28 +168,44 @@ public static void DestroyPathsPlusPlusSliders() Pathsplusplussliders.Clear(); } } + + public static void ApplyPathsPlusPlusSliders(TowerModel? tower) + { + if (!Main.HasPathsPlusPlus) return; + if (tower == null) return; + foreach (var path in GetContent().Where(p => p.Tower == tower.baseId)) + { + if (Pathsplusplussliders.All(p => p.Value.name.Split(':')[1] != path.Id)) continue; + ApplyPathPlusPlus(path, (int)Pathsplusplussliders.First(p => p.Value.name.Split(':')[1] == path.Id).Value.CurrentValue, tower); + } + } public static void GeneratePathsPlusPlusSliders(string baseId) { if (!Main.HasPathsPlusPlus) return; DestroyPathsPlusPlusSliders(); - + + if(GetContent().All(p => p.Tower != baseId)) + return; + foreach (var path in GetContent().Where(p => p.Tower == baseId)) { var i = path.Path + 1; var currentpath = pathselect.AddPanel(new Info($"Path{i}", 290, 300), VanillaSprites.BrownInsertPanel); currentpath.AddText(new Info($"Path{i}Text", 290, 100, new Vector2(.5f, .85f)), $"Path {i}", 50f); - var slider = currentpath.AddSlider(new Info($"Path{i}Input", 180, 60, new Vector2(.5f, .35f)), 0, 0, 5, + var slider = currentpath.AddSlider(new Info($"Path{i}Input:{path.Id}", 180, 60, new Vector2(.5f, .35f)), 0, 0, 5, 1, new Vector2(85, 85), new Action( - tier => + _ => { Main.selectedtower = InGame.instance.GetGameModel().GetTowerModel(Main.selectedBaseID, (int)Pathsliders[0].CurrentValue, (int)Pathsliders[1].CurrentValue, - (int)Pathsliders[2].CurrentValue); - ApplyPathPlusPlus(path,(int)tier, ref Main.selectedtower); + (int)Pathsliders[2].CurrentValue)?.Duplicate(); + + ApplyPathsPlusPlusSliders(Main.selectedtower); + UpdateBottomBar(); } )); @@ -188,10 +213,9 @@ public static void GeneratePathsPlusPlusSliders(string baseId) Object.Destroy(slider.DefaultNotch.gameObject); pathselect.AddScrollContent(currentpath); Pathsplusplussliders[i] = slider; - - pathselect.ScrollRect.enabled = true; - pathselect.ScrollRect.horizontalNormalizedPosition = 0f; } + pathselect.ScrollRect.enabled = true; + pathselect.ScrollRect.horizontalNormalizedPosition = 0f; } public static void CreateTowerSetButton(string name, string icon, string background, @@ -207,10 +231,9 @@ public static void CreateTowerSetButton(string name, string icon, string backgro towersetselect.AddScrollContent(towersetpanel); var towersinset = new List(); - + if (modtowerset != null) - foreach (var tower in InGame.instance.GetGameModel().towerSet.Select(model => model.GetTower()) - .Where(tower => tower.GetModTower()?.GetPropertyValue("ModTowerSet") == modtowerset)) + foreach (var tower in InGame.instance.GetGameModel().towerSet.Select(model => model.GetTower()).Where(tower => tower.GetModTower()?.GetPropertyValue("ModTowerSet") == modtowerset)) { var towerpanel = towersetpanel.AddButton(new Info(tower.name, width, 290), background, new Action(() => @@ -240,8 +263,9 @@ public static void CreateTowerSetButton(string name, string icon, string backgro Main.selectedtower = InGame.instance.GetGameModel().GetTowerModel(Main.selectedBaseID, (int)Pathsliders[0].CurrentValue, (int)Pathsliders[1].CurrentValue, - (int)Pathsliders[2].CurrentValue); - + (int)Pathsliders[2].CurrentValue)?.Duplicate(); + + ApplyPathsPlusPlusSliders(Main.selectedtower); UpdateBottomBar(); UnlockInputFields(); @@ -294,7 +318,7 @@ public static void CreateTowerSetButton(string name, string icon, string backgro if (towerSet == TowerSet.Hero) { Main.selectedtower = InGame.instance.GetGameModel() - .GetTowerModel(tower.baseId, (int)levelslider.CurrentValue); + .GetTowerModel(tower.baseId, (int)levelslider.CurrentValue)?.Duplicate(); pathselect.SetActive(false); levelselect.SetActive(true); } @@ -304,7 +328,10 @@ public static void CreateTowerSetButton(string name, string icon, string backgro pathselect.SetActive(true); Main.selectedtower = InGame.instance.GetGameModel().GetTowerModel(tower.baseId, (int)Pathsliders[0].CurrentValue, (int)Pathsliders[1].CurrentValue, - (int)Pathsliders[2].CurrentValue); + (int)Pathsliders[2].CurrentValue)?.Duplicate(); + + if (Main.HasPathsPlusPlus) + ApplyPathsPlusPlusSliders(Main.selectedtower); } towersetpanel.transform.parent.FindChild(tower.name).FindChild("TowerSelected").gameObject @@ -349,7 +376,6 @@ public static void CreateTowerSetButton(string name, string icon, string backgro public static void UpdateBottomBar() { - if (Main.selectedtower == null || !ValidTiers(Main.selectedtower.tiers.Concat(Pathsplusplussliders.Values.Select(slider => (int)slider.CurrentValue)).ToList())) { invalidtext.gameObject.SetActive(true); @@ -361,12 +387,7 @@ public static void UpdateBottomBar() mergetext.Text.color = mergebutton.Button.colors.disabledColor; return; } - - if (Pathsplusplussliders.Values.All(x => x.CurrentValue == 0) && Main.selectedtower.tiers.All(x => x == 0)) - { - Main.selectedtower.portrait = CreateSpriteReference(Game.instance.model.GetTower(Main.selectedtower.baseId).portrait.guidRef); - } - + invalidtext.gameObject.SetActive(false); cost.gameObject.SetActive(true); mergebutton.Button.interactable = true;