diff --git a/Assemblies/CombatRealism.dll b/Assemblies/CombatRealism.dll index b1e87a9..e008499 100644 Binary files a/Assemblies/CombatRealism.dll and b/Assemblies/CombatRealism.dll differ diff --git a/Source/CombatRealism/Detours/DetourInjector.cs b/Source/CombatRealism/Detours/DetourInjector.cs index 86e8db3..5b869f5 100644 --- a/Source/CombatRealism/Detours/DetourInjector.cs +++ b/Source/CombatRealism/Detours/DetourInjector.cs @@ -1,140 +1,149 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Reflection; -using RimWorld; -using Verse; -using UnityEngine; -using CommunityCoreLibrary; - -namespace Combat_Realism.Detours -{ - class DetourInjector : SpecialInjector - { - public override bool Inject() - { - // Detour VerbsTick - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(VerbTracker).GetMethod("VerbsTick", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_VerbTracker).GetMethod("VerbsTick", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // Detour TooltipUtility - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(TooltipUtility).GetMethod("ShotCalculationTipString", BindingFlags.Static | BindingFlags.Public), - typeof(Detours_TooltipUtility).GetMethod("ShotCalculationTipString", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // Detour FloatMenuMaker - if(!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(FloatMenuMaker).GetMethod("ChoicesAtFor", BindingFlags.Static | BindingFlags.Public), - typeof(Detours_FloatMenuMaker).GetMethod("ChoicesAtFor", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // ************************************* - // *** Detour Inventory methods *** - // ************************************* - - // ThingContainer - - MethodInfo tryAddSource = typeof(ThingContainer).GetMethod("TryAdd", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Thing) }, null); - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryAddSource, typeof(Detours_ThingContainer).GetMethod("TryAdd", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - MethodInfo tryDrop2Source = typeof(ThingContainer).GetMethod("TryDrop", - BindingFlags.Instance | BindingFlags.Public, - null, - new Type[] { typeof(Thing), typeof(IntVec3), typeof(ThingPlaceMode), typeof(int), typeof(Thing).MakeByRefType() }, - null); - - MethodInfo tryDrop2Dest = typeof(Detours_ThingContainer).GetMethod("TryDrop", - BindingFlags.Static | BindingFlags.NonPublic, - null, - new Type[] { typeof(ThingContainer), typeof(Thing), typeof(IntVec3), typeof(ThingPlaceMode), typeof(int), typeof(Thing).MakeByRefType() }, - null); - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryDrop2Source, tryDrop2Dest)) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(ThingContainer).GetMethod("Get", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_ThingContainer).GetMethod("Get", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(ThingContainer).GetMethod("Remove", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_ThingContainer).GetMethod("Remove", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // Pawn_ApparelTracker - - MethodInfo tryDrop3Source = typeof(Pawn_ApparelTracker).GetMethod("TryDrop", - BindingFlags.Instance | BindingFlags.Public, - null, - new Type[] { typeof(Apparel), typeof(Apparel).MakeByRefType(), typeof(IntVec3), typeof(bool) }, - null); - - MethodInfo tryDrop3Dest = typeof(Detours_Pawn_ApparelTracker).GetMethod("TryDrop", - BindingFlags.Static | BindingFlags.NonPublic, - null, - new Type[] { typeof(Pawn_ApparelTracker), typeof(Apparel), typeof(Apparel).MakeByRefType(), typeof(IntVec3), typeof(bool) }, - null); - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryDrop3Source, tryDrop3Dest)) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_ApparelTracker).GetMethod("Wear", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Pawn_ApparelTracker).GetMethod("Wear", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_ApparelTracker).GetMethod("Notify_WornApparelDestroyed", BindingFlags.Instance | BindingFlags.NonPublic), - typeof(Detours_Pawn_ApparelTracker).GetMethod("Notify_WornApparelDestroyed", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // Pawn_EquipmentTracker - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("AddEquipment", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Pawn_EquipmentTracker).GetMethod("AddEquipment", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("Notify_PrimaryDestroyed", BindingFlags.Instance | BindingFlags.NonPublic), - typeof(Detours_Pawn_EquipmentTracker).GetMethod("Notify_PrimaryDestroyed", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryDropEquipment", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryDropEquipment", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryTransferEquipmentToContainer", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryTransferEquipmentToContainer", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryStartAttack", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryStartAttack", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // ************************************* - // *** Detour inventory-related methods *** - // ************************************* - - // WorkGiver_InteractAnimal - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(WorkGiver_InteractAnimal).GetMethod("TakeFoodForAnimalInteractJob", BindingFlags.Instance | BindingFlags.NonPublic), - typeof(Detours_WorkGiver_InteractAnimal).GetMethod("TakeFoodForAnimalInteractJob", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // WorkGiver_HunterHunt - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(WorkGiver_HunterHunt).GetMethod("HasHuntingWeapon", BindingFlags.Static | BindingFlags.Public), - typeof(Detours_WorkGiver_HunterHunt).GetMethod("HasHuntingWeapon", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // Tradeable - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Tradeable).GetMethod("PriceFor", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_Tradeable).GetMethod("PriceFor", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - // TradeDeal - if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(TradeDeal).GetMethod("UpdateCurrencyCount", BindingFlags.Instance | BindingFlags.Public), - typeof(Detours_TradeDeal).GetMethod("UpdateCurrencyCount", BindingFlags.Static | BindingFlags.NonPublic))) - return false; - - - return true; - } - } -} +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using RimWorld; +using Verse; +using Verse.AI; +using UnityEngine; +using CommunityCoreLibrary; + +namespace Combat_Realism.Detours +{ + class DetourInjector : SpecialInjector + { + public override bool Inject() + { + // Detour VerbsTick + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(VerbTracker).GetMethod("VerbsTick", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_VerbTracker).GetMethod("VerbsTick", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // Detour TooltipUtility + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(TooltipUtility).GetMethod("ShotCalculationTipString", BindingFlags.Static | BindingFlags.Public), + typeof(Detours_TooltipUtility).GetMethod("ShotCalculationTipString", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // Detour FloatMenuMaker + if(!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(FloatMenuMaker).GetMethod("ChoicesAtFor", BindingFlags.Static | BindingFlags.Public), + typeof(Detours_FloatMenuMaker).GetMethod("ChoicesAtFor", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // ************************************* + // *** Detour Inventory methods *** + // ************************************* + + // ThingContainer + + MethodInfo tryAddSource = typeof(ThingContainer).GetMethod("TryAdd", BindingFlags.Instance | BindingFlags.Public, null, new Type[] { typeof(Thing) }, null); + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryAddSource, typeof(Detours_ThingContainer).GetMethod("TryAdd", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + MethodInfo tryDrop2Source = typeof(ThingContainer).GetMethod("TryDrop", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(Thing), typeof(IntVec3), typeof(ThingPlaceMode), typeof(int), typeof(Thing).MakeByRefType() }, + null); + + MethodInfo tryDrop2Dest = typeof(Detours_ThingContainer).GetMethod("TryDrop", + BindingFlags.Static | BindingFlags.NonPublic, + null, + new Type[] { typeof(ThingContainer), typeof(Thing), typeof(IntVec3), typeof(ThingPlaceMode), typeof(int), typeof(Thing).MakeByRefType() }, + null); + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryDrop2Source, tryDrop2Dest)) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(ThingContainer).GetMethod("Get", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_ThingContainer).GetMethod("Get", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(ThingContainer).GetMethod("Remove", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_ThingContainer).GetMethod("Remove", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // Pawn_ApparelTracker + + MethodInfo tryDrop3Source = typeof(Pawn_ApparelTracker).GetMethod("TryDrop", + BindingFlags.Instance | BindingFlags.Public, + null, + new Type[] { typeof(Apparel), typeof(Apparel).MakeByRefType(), typeof(IntVec3), typeof(bool) }, + null); + + MethodInfo tryDrop3Dest = typeof(Detours_Pawn_ApparelTracker).GetMethod("TryDrop", + BindingFlags.Static | BindingFlags.NonPublic, + null, + new Type[] { typeof(Pawn_ApparelTracker), typeof(Apparel), typeof(Apparel).MakeByRefType(), typeof(IntVec3), typeof(bool) }, + null); + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(tryDrop3Source, tryDrop3Dest)) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_ApparelTracker).GetMethod("Wear", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Pawn_ApparelTracker).GetMethod("Wear", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_ApparelTracker).GetMethod("Notify_WornApparelDestroyed", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(Detours_Pawn_ApparelTracker).GetMethod("Notify_WornApparelDestroyed", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // Pawn_EquipmentTracker + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("AddEquipment", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Pawn_EquipmentTracker).GetMethod("AddEquipment", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("Notify_PrimaryDestroyed", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(Detours_Pawn_EquipmentTracker).GetMethod("Notify_PrimaryDestroyed", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryDropEquipment", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryDropEquipment", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryTransferEquipmentToContainer", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryTransferEquipmentToContainer", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Pawn_EquipmentTracker).GetMethod("TryStartAttack", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Pawn_EquipmentTracker).GetMethod("TryStartAttack", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // ************************************* + // *** Detour inventory-related methods *** + // ************************************* + + // WorkGiver_InteractAnimal + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(WorkGiver_InteractAnimal).GetMethod("TakeFoodForAnimalInteractJob", BindingFlags.Instance | BindingFlags.NonPublic), + typeof(Detours_WorkGiver_InteractAnimal).GetMethod("TakeFoodForAnimalInteractJob", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // WorkGiver_HunterHunt + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(WorkGiver_HunterHunt).GetMethod("HasHuntingWeapon", BindingFlags.Static | BindingFlags.Public), + typeof(Detours_WorkGiver_HunterHunt).GetMethod("HasHuntingWeapon", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // Tradeable + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(Tradeable).GetMethod("PriceFor", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_Tradeable).GetMethod("PriceFor", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // TradeDeal + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(TradeDeal).GetMethod("UpdateCurrencyCount", BindingFlags.Instance | BindingFlags.Public), + typeof(Detours_TradeDeal).GetMethod("UpdateCurrencyCount", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + // ************************************* + // ******** AI-related methods ********* + // ************************************* + + // AttackTargetFinder + if (!CommunityCoreLibrary.Detours.TryDetourFromTo(typeof(AttackTargetFinder).GetMethod("BestAttackTarget", BindingFlags.Static | BindingFlags.Public), + typeof(Detour_AttackTargetFinder).GetMethod("BestAttackTarget", BindingFlags.Static | BindingFlags.NonPublic))) + return false; + + return true; + } + } +} diff --git a/Source/CombatRealism/Detours/Detour_AttackTargetFinder.cs b/Source/CombatRealism/Detours/Detour_AttackTargetFinder.cs new file mode 100644 index 0000000..f7d97e6 --- /dev/null +++ b/Source/CombatRealism/Detours/Detour_AttackTargetFinder.cs @@ -0,0 +1,181 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Reflection; +using RimWorld; +using Verse; +using Verse.AI; +using UnityEngine; +using CommunityCoreLibrary; + + +namespace Combat_Realism.Detours +{ + public static class Detour_AttackTargetFinder + { + internal static List tmpTargets = new List(); + + internal static List tempDestList = new List(); + + internal static List tempSourceList = new List(); + + internal static Thing BestAttackTarget(Thing searcher, Predicate validator, float maxTargDist, float minTargDist, TargetScanFlags flags, IntVec3 locus = default(IntVec3), float maxTravelRadiusFromLocus = 3.40282347E+38f) + { + Pawn searcherPawn = searcher as Pawn; + Verb attackVerb = Detour_AttackTargetFinder.GetAttackVerb(searcher); + if (attackVerb == null) + { + Log.Error("BestAttackTarget with " + searcher + " who has no attack verb."); + return null; + } + bool onlyTargetMachines = attackVerb != null && attackVerb.verbProps.projectileDef != null && attackVerb.verbProps.projectileDef.projectile.damageDef == DamageDefOf.EMP; + float minDistanceSquared = minTargDist * minTargDist; + float num = maxTravelRadiusFromLocus + attackVerb.verbProps.range; + float maxLocusDistSquared = num * num; + Predicate predicate = delegate (Thing t) + { + if (t == searcher) + { + return false; + } + if (minDistanceSquared > 0f && (searcher.Position - t.Position).LengthHorizontalSquared < minDistanceSquared) + { + return false; + } + if (maxTravelRadiusFromLocus < 9999f && (t.Position - locus).LengthHorizontalSquared > maxLocusDistSquared) + { + return false; + } + if (!searcher.HostileTo(t)) + { + return false; + } + if (validator != null && !validator(t)) + { + return false; + } + if ((byte)(flags & TargetScanFlags.NeedLOSToAll) != 0 && !searcher.CanSee(t)) + { + if (t is Pawn) + { + if ((byte)(flags & TargetScanFlags.NeedLOSToPawns) != 0) + { + return false; + } + } + else if ((byte)(flags & TargetScanFlags.NeedLOSToNonPawns) != 0) + { + return false; + } + } + if ((byte)(flags & TargetScanFlags.NeedThreat) != 0 && ((IAttackTarget)t).ThreatDisabled()) + { + return false; + } + Pawn pawn = t as Pawn; + if (onlyTargetMachines && pawn != null && pawn.RaceProps.IsFlesh) + { + return false; + } + if ((byte)(flags & TargetScanFlags.NeedNonBurning) != 0 && t.IsBurning()) + { + return false; + } + if (searcher.def.race != null && searcher.def.race.intelligence >= Intelligence.Humanlike) + { + CompExplosive compExplosive = t.TryGetComp(); + if (compExplosive != null && compExplosive.wickStarted) + { + return false; + } + } + return true; + }; + if (Detour_AttackTargetFinder.HasRangedAttack(searcher)) + { + Detour_AttackTargetFinder.tmpTargets.Clear(); + List potentialTargetsFor = Find.AttackTargetsCache.GetPotentialTargetsFor(searcher); + for (int i = 0; i < potentialTargetsFor.Count; i++) + { + Detour_AttackTargetFinder.tmpTargets.Add((Thing)potentialTargetsFor[i]); + } + Thing result = GenClosest.ClosestThing_Global(searcher.Position, Detour_AttackTargetFinder.tmpTargets, maxTargDist, predicate); + Detour_AttackTargetFinder.tmpTargets.Clear(); + return result; + } + if (searcherPawn != null && searcherPawn.mindState.duty != null && searcherPawn.mindState.duty.radius > 0f) + { + Predicate oldValidator = predicate; + predicate = ((Thing t) => oldValidator(t) && t.Position.InHorDistOf(searcherPawn.mindState.duty.focus.Cell, searcherPawn.mindState.duty.radius)); + } + int searchRegionsMax = (maxTargDist <= 800f) ? 40 : -1; + return GenClosest.ClosestThingReachable(searcher.Position, ThingRequest.ForGroup(ThingRequestGroup.AttackTarget), PathEndMode.Touch, TraverseParms.For(searcherPawn, Danger.Deadly, TraverseMode.ByPawn, false), maxTargDist, predicate, null, searchRegionsMax, false); + } + + internal static Verb GetAttackVerb(Thing attacker) + { + Pawn pawn = attacker as Pawn; + if (pawn != null) + { + return pawn.TryGetAttackVerb(!pawn.IsColonist); + } + Building_Turret building_Turret = attacker as Building_Turret; + if (building_Turret != null) + { + return building_Turret.AttackVerb; + } + return null; + } + + internal static bool HasRangedAttack(Thing t) + { + if (t is Building_Turret) + { + return true; + } + Pawn pawn = t as Pawn; + if (pawn == null) + { + Log.ErrorOnce("Unknown target searcher: " + t, 7547344); + return true; + } + Thing thing = pawn.MannedThing(); + if (thing != null && thing is Building_Turret) + { + return true; + } + Verb verb = pawn.TryGetAttackVerb(true); + return verb != null && !verb.verbProps.MeleeRange; + } + + public static Thing BestShootTargetFromCurrentPosition(Thing searcher, Predicate validator, float maxDistance, float minDistance, TargetScanFlags flags) + { + return Detour_AttackTargetFinder.BestAttackTarget(searcher, validator, maxDistance, minDistance, flags, default(IntVec3), 3.40282347E+38f); + } + + public static bool CanSee(this Thing seer, Thing target) + { + ShootLeanUtility.CalcShootableCellsOf(Detour_AttackTargetFinder.tempDestList, target); + for (int i = 0; i < Detour_AttackTargetFinder.tempDestList.Count; i++) + { + if (GenSight.LineOfSight(seer.Position, Detour_AttackTargetFinder.tempDestList[i], true)) + { + return true; + } + } + ShootLeanUtility.LeanShootingSourcesFromTo(seer.Position, target.Position, Detour_AttackTargetFinder.tempSourceList); + for (int j = 0; j < Detour_AttackTargetFinder.tempSourceList.Count; j++) + { + for (int k = 0; k < Detour_AttackTargetFinder.tempDestList.Count; k++) + { + if (GenSight.LineOfSight(Detour_AttackTargetFinder.tempSourceList[j], Detour_AttackTargetFinder.tempDestList[k], true)) + { + return true; + } + } + } + return false; + } + } +}