diff --git a/Defs/ThingDefs_Items/Items_Resource_Ammo.xml b/Defs/ThingDefs_Items/Items_Resource_Ammo.xml
index e191e67878..cbcbbac74e 100644
--- a/Defs/ThingDefs_Items/Items_Resource_Ammo.xml
+++ b/Defs/ThingDefs_Items/Items_Resource_Ammo.xml
@@ -4,7 +4,6 @@
- CombatExtended.AmmoThing
Prometheum
Military-grade incendiary agent, ignites on contact with oxygen. The raw resource is used to craft incendiary ammo of all kinds.
@@ -46,7 +45,6 @@
- CombatExtended.AmmoThing
FSX
High-explosive chemical extracted from Boomalope sacks and synthesized from chemfuel, it is used in a variety of industrial and military applications.
diff --git a/Source/CombatExtended.sln b/Source/CombatExtended.sln
index 699530c978..185860b847 100644
--- a/Source/CombatExtended.sln
+++ b/Source/CombatExtended.sln
@@ -15,6 +15,8 @@ Project("{E9B3A09D-DD32-4429-ABCC-64A2EA58B0B3}") = "ArtilleryCompat", "Artiller
EndProject
Project("{B55F2CBF-ABFF-4E01-813B-79DAAAC20203}") = "VehiclesCompat", "VehiclesCompat\VehiclesCompat.csproj", "{06833316-A463-4044-BAA7-993683F9810B}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SRTSCompat", "SRTSCompat\SRTSCompat.csproj", "{2ECDEC68-5878-41C7-B494-E189B8C5C33E}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -58,7 +60,12 @@ Global
{06833316-A463-4044-BAA7-993683F9810B}.Debugger|Any CPU.Build.0 = Debug|Any CPU
{06833316-A463-4044-BAA7-993683F9810B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{06833316-A463-4044-BAA7-993683F9810B}.Release|Any CPU.Build.0 = Release|Any CPU
-
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Debugger|Any CPU.ActiveCfg = Debug|Any CPU
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Debugger|Any CPU.Build.0 = Debug|Any CPU
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {2ECDEC68-5878-41C7-B494-E189B8C5C33E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/Source/CombatExtended/Compatibility/SRTS.cs b/Source/CombatExtended/Compatibility/SRTS.cs
new file mode 100644
index 0000000000..065e2239bd
--- /dev/null
+++ b/Source/CombatExtended/Compatibility/SRTS.cs
@@ -0,0 +1,35 @@
+using HarmonyLib;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using Verse;
+using Verse.Sound;
+using System.Reflection.Emit;
+using System;
+using UnityEngine;
+using RimWorld;
+
+namespace CombatExtended.Compatibility
+{
+ public class SRTS : IPatch
+ {
+ public bool CanInstall()
+ {
+ Log.Message("Combat Extended :: Checking SRTS Expanded");
+ if (!ModLister.HasActiveModWithName("SRTS Expanded"))
+ {
+ return false;
+ }
+ return true;
+ }
+ public IEnumerable GetCompatList()
+ {
+ yield return "SRTSCompat";
+ }
+
+ public void Install()
+ {
+ Log.Message("Combat Extended :: Installing SRTS Expanded");
+ }
+ }
+}
diff --git a/Source/SRTSCompat/SRTSCompat.csproj b/Source/SRTSCompat/SRTSCompat.csproj
new file mode 100644
index 0000000000..0286358d4c
--- /dev/null
+++ b/Source/SRTSCompat/SRTSCompat.csproj
@@ -0,0 +1,58 @@
+
+
+
+ net48
+ SRTSCompat
+ 1.1.2.0
+ 1.1.2.0
+ 1.1.2
+
+
+ CC BY-NC-SA 4.0 2022
+ false
+
+
+ ..\..\AssembliesCompat\
+ portable
+ true
+ true
+ 8.0
+ true
+
+
+ ..\..\AssembliesCompat\
+ true
+ none
+ false
+ 8.0
+ true
+
+
+
+
+
+
+
+
+
+
+ False
+
+
+
+
+ ..\..\Assemblies\0CombatExtendedLoader.dll
+ False
+
+
+
+
+ ..\packages\SRTS-reference.dll
+ False
+
+
+
+
+
+
+
diff --git a/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_BomberSkyfaller.cs b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_BomberSkyfaller.cs
new file mode 100644
index 0000000000..73f5079d55
--- /dev/null
+++ b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_BomberSkyfaller.cs
@@ -0,0 +1,140 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using Verse;
+using CombatExtended.Loader;
+using RimWorld;
+using System.Collections.Generic;
+using HarmonyLib;
+using SRTS;
+using SPExtended;
+using UnityEngine;
+
+namespace CombatExtended.Compatibility.SRTSCompat
+{
+ [HarmonyPatch(typeof(BomberSkyfaller),
+ "DropBomb",
+ new Type[] { })]
+ [HarmonyPriority(Priority.First)]
+ public static class Harmony_BomberSkyfaller_DropBomb
+ {
+ private static MethodInfo GetCurrentTargetingRadiusInfo = AccessTools.DeclaredMethod(
+ typeof(BomberSkyfaller), "GetCurrentTargetingRadius", new Type[] { });
+
+ private static float shotHeight = 5f;
+
+ // A destructive prefix so as to force SRTS bombers to use our projectile system,
+ // unless the bomb isn't an AmmoThing, if so, fall back to SRTS's bombing system.
+ public static bool Prefix(BomberSkyfaller __instance)
+ {
+ ActiveDropPod srts = (ActiveDropPod)__instance.innerContainer.First();
+ if (srts == null)
+ {
+ goto FunctionEnd;
+ }
+
+ for (int i = 0; i < (__instance.bombType == BombingType.precise
+ ? __instance.precisionBombingNumBombs : 1); ++i)
+ {
+ Thing bombStack = srts.Contents.innerContainer
+ .FirstOrDefault(thing => SRTSMod.mod.settings.allowedBombs.Contains(thing.def.defName));
+ if (bombStack == null)
+ {
+ goto FunctionEnd;
+ }
+
+ Thing bombThing = srts.Contents.innerContainer.Take(bombStack, 1);
+
+ IntVec3 bombPos = __instance.bombCells[0];
+ if (__instance.bombType == BombingType.carpet)
+ {
+ __instance.bombCells.RemoveAt(0);
+ }
+
+ object targetingRadiusNullable = GetCurrentTargetingRadiusInfo.Invoke(__instance, null);
+ if (targetingRadiusNullable == null)
+ {
+ Log.Error("Combat Extended :: SRTSCompat BomberSkyfaller.DropBomb() - "
+ + "could not get SRTS dropship's targeting radius");
+ throw new Exception();
+ }
+ float targetingRadius = (float)(int)targetingRadiusNullable;
+
+ if (bombThing is AmmoThing)
+ {
+ // Combat Extended projectile system
+ ThingDef bombProjectileThingDef = (bombThing.def as AmmoDef)?.AmmoSetDefs
+ .Find(ammoSet => ammoSet.ammoTypes?.Any() ?? false)?
+ .ammoTypes
+ .FirstOrDefault(ammoLink => ammoLink.ammo == bombThing.def)?
+ .projectile;
+ if (bombProjectileThingDef == null)
+ {
+ Log.Error("Combat Extended :: SRTSCompat Harmony_BomberSkyfaller_DropBomb Prefix - "
+ + $"AmmoDef {bombThing.def} doesn't have a projectile");
+ throw new Exception();
+ }
+
+ ProjectilePropertiesCE bombPropsCE = bombProjectileThingDef.projectile as ProjectilePropertiesCE;
+ if (bombPropsCE == null)
+ {
+ Log.Error("Combat Extended :: SRTSCompat Harmony_BomberSkyfaller_DropBomb Prefix - "
+ + $"AmmoDef {bombThing.def} projectile doesn't have ProjectilePropsCE");
+ throw new Exception();
+ }
+
+ ProjectileCE bombProjectileCE = ThingMaker.MakeThing(bombProjectileThingDef) as ProjectileCE;
+
+ GenSpawn.Spawn(bombProjectileCE, __instance.DrawPosCell, __instance.Map);
+ bombProjectileCE.canTargetSelf = false;
+ bombProjectileCE.minCollisionDistance = 1;
+ bombProjectileCE.intendedTarget = null;
+ bombProjectileCE.AccuracyFactor = 1f;
+
+ float freefallTime = Mathf.Sqrt(2 * shotHeight / bombPropsCE.Gravity);
+ float maxShotSpeed = targetingRadius / freefallTime;
+
+ bombProjectileCE.Launch(launcher: __instance,
+ origin: __instance.DrawPosCell.ToIntVec2.ToVector2(),
+ shotAngle: 0f,
+ shotRotation: Rand.Range(-180f, 180f),
+ shotHeight: shotHeight,
+ shotSpeed: Rand.Range(0f, maxShotSpeed),
+ equipment: __instance);
+ // Adjust shot speed after because of
+ // this.shotSpeed = Math.Max(shotSpeed, def.projectile.speed);
+ bombProjectileCE.shotSpeed = Rand.Range(0f, maxShotSpeed);
+ }
+ else
+ {
+ // Original SRTS bomb dropping system
+ int timerTickExplode = 20 + Rand.Range(0, 5);
+
+ FallingBomb fallingBombThing = new FallingBomb(bombThing,
+ bombThing.TryGetComp(),
+ __instance.Map,
+ __instance.def.skyfaller.shadow);
+ fallingBombThing.HitPoints = int.MaxValue;
+ fallingBombThing.ticksRemaining = timerTickExplode;
+
+ IntVec3 targetCell = GenRadial.RadialCellsAround(bombPos, targetingRadius, true)
+ .Where(cell => cell.InBounds(__instance.Map))
+ .RandomElementByWeight(cell => 1f - Mathf.Min(cell.DistanceTo(__instance.Position) / targetingRadius, 1f) + 0.05f);
+
+ fallingBombThing.angle = __instance.angle + (SPTrig.LeftRightOfLine(__instance.DrawPosCell, __instance.Position, targetCell) * -10);
+ fallingBombThing.speed = (float)SPExtra.Distance(__instance.DrawPosCell, targetCell) / fallingBombThing.ticksRemaining;
+ Thing t = GenSpawn.Spawn(fallingBombThing, targetCell, __instance.Map);
+ GenExplosion.NotifyNearbyPawnsOfDangerousExplosive(t, bombThing.TryGetComp().Props.explosiveDamageType, null);
+ }
+ }
+
+ FunctionEnd:
+ if (__instance.bombType == BombingType.precise && __instance.bombCells.Any())
+ {
+ __instance.bombCells.Clear();
+ }
+ return false;
+ }
+ }
+}
diff --git a/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_DialogSettings.cs b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_DialogSettings.cs
new file mode 100644
index 0000000000..465a8be226
--- /dev/null
+++ b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_DialogSettings.cs
@@ -0,0 +1,134 @@
+using System;
+using System.Diagnostics;
+using System.Globalization;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using Verse;
+using CombatExtended.Loader;
+using RimWorld;
+using System.Collections.Generic;
+using HarmonyLib;
+using SRTS;
+using UnityEngine;
+
+namespace CombatExtended.Compatibility.SRTSCompat
+{
+ [HarmonyPatch(typeof(Dialog_AllowedBombs),
+ nameof(Dialog_AllowedBombs.DoWindowContents),
+ new Type[] { typeof(Rect) })]
+ public static class Harmony_Dialog_AllowedBombs_DoWindowContents_Rect
+ {
+ static FieldInfo explosivesStringInfo = AccessTools.DeclaredField(typeof(Dialog_AllowedBombs),
+ "explosivesString");
+ public static List SearchForExplosives(Dialog_AllowedBombs __instance)
+ {
+ // You think this is bad? Imagine how it'd be as a single line
+ return DefDatabase.AllDefs
+ .Where(thingDef => !SRTSMod.mod.settings.allowedBombs.Contains(thingDef.defName)
+ && thingDef.building is null
+ && !thingDef.IsWeapon
+ && !thingDef.IsApparel
+ && thingDef.projectile == null
+ && 0 <= CultureInfo.CurrentCulture.CompareInfo.IndexOf(thingDef.defName,
+ explosivesStringInfo.GetValue(__instance) as string,
+ CompareOptions.IgnoreCase)
+ && (thingDef.GetCompProperties() != null
+ || ((thingDef as AmmoDef)?.AmmoSetDefs?
+ .Any(ammoSetDef => ammoSetDef.ammoTypes?
+ .Any(ammoLink => ammoLink.projectile.GetCompProperties() != null
+ || ammoLink.projectile.projectile?.explosionRadius > 0.5f)
+ ?? false)
+ ?? false)
+ )
+ )
+ .ToList();
+ }
+
+ /// Replaces
+ // if (SRTSHelper.CEModLoaded)
+ // {
+ // explosivesSearched = DefDatabase.AllDefs
+ // .Where(x => x.HasComp(Type.GetType("CombatExtended.CompExplosiveCE,CombatExtended"))
+ // && !SRTSMod.mod.settings.allowedBombs.Contains(x.defName)
+ // && CultureInfo.CurrentCulture.CompareInfo.IndexOf(x.defName, explosivesString, CompareOptions.IgnoreCase) >= 0)
+ // .ToList();
+ // }
+ // else
+ // {
+ // explosivesSearched = DefDatabase.AllDefs
+ // .Where(x => x.GetCompProperties() != null
+ // && x.building is null
+ // && !SRTSMod.mod.settings.allowedBombs.Contains(x.defName)
+ // && CultureInfo.CurrentCulture.CompareInfo.IndexOf(x.defName, explosivesString, CompareOptions.IgnoreCase) >= 0)
+ // .ToList();
+ // }
+ /// With
+ // explosivesSearched = Harmony_Dialog_AllowedBombs_DoWindowContents_Rect.SearchForExplosives(this);
+ static IEnumerable Transpiler(IEnumerable instructions,
+ ILGenerator il)
+ {
+ bool found = false;
+
+ FieldInfo explosivesChangedField = AccessTools.DeclaredField(typeof(Dialog_AllowedBombs),
+ "explosivesChanged");
+ CodeInstruction callIns = CodeInstruction.Call(
+ typeof(Harmony_Dialog_AllowedBombs_DoWindowContents_Rect),
+ "SearchForExplosives",
+ new Type[] { typeof(Dialog_AllowedBombs) });
+
+ List codes = instructions.ToList();
+ for (int i = 0; i < codes.Count(); ++i)
+ {
+ if (!found && i > 1
+ && codes[i - 2].opcode == OpCodes.Ldc_I4_0
+ && codes[i - 1].StoresField(explosivesChangedField))
+ {
+ found = true;
+
+ if (callIns == null)
+ {
+ Log.Error("Combat Extended :: SRTSCompat Dialog_AllowedBombs.DoWindowContents(Rect) - "
+ + "tried patching, but no function to patch with");
+ goto SkipTranspile;
+ }
+
+ Label? skipToLabel = null;
+ for (int j = i; j >= 0; --j)
+ {
+ if (codes[j].Branches(out skipToLabel))
+ {
+ break;
+ }
+ }
+ if (skipToLabel == null)
+ {
+ Log.Error("Combat Extended :: SRTSCompat Dialog_AllowedBombs.DoWindowContents(Rect) - "
+ + "didn't find any branch to labels before the target; did we even find the target?");
+ goto SkipTranspile;
+ }
+
+ yield return new CodeInstruction(OpCodes.Ldarg_0);
+ yield return new CodeInstruction(OpCodes.Ldarg_0);
+ yield return callIns;
+ yield return CodeInstruction.StoreField(typeof(Dialog_AllowedBombs), "explosivesSearched");
+
+ while (i < codes.Count() && !codes[i].labels.Any(label => label == skipToLabel))
+ {
+ ++i;
+ }
+ if (codes.Count() == i)
+ {
+ Log.Error("Combat Extended :: SRTSCompat Dialog_AllowedBombs.DoWindowContents(Rect) - "
+ + "we skipped over the entire code without finding the skip label. "
+ + "If you're reading this, know that your bombs selection menu is now screwed :)");
+ }
+ }
+
+ SkipTranspile:
+ yield return codes[i];
+ }
+ }
+ }
+
+}
diff --git a/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_FallingBomb.cs b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_FallingBomb.cs
new file mode 100644
index 0000000000..997c4838cf
--- /dev/null
+++ b/Source/SRTSCompat/SRTSCompat/Harmony/Harmony_FallingBomb.cs
@@ -0,0 +1,51 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Emit;
+using Verse;
+using CombatExtended.Loader;
+using RimWorld;
+using System.Collections.Generic;
+using HarmonyLib;
+using SRTS;
+using UnityEngine;
+
+namespace CombatExtended.Compatibility.SRTSCompat
+{
+ [HarmonyPatch(typeof(FallingBomb),
+ MethodType.Constructor,
+ new Type[] { typeof(Thing), typeof(CompExplosive), typeof(Map), typeof(string) })]
+ public static class Harmony_FallingBomb_Thing_CompExplosive_Map_string
+ {
+ // Adds an additional null check for def.projectileWhenLoaded of
+ // this.projectile = def.projectileWhenLoaded.projectile;
+ static IEnumerable Transpiler(IEnumerable instructions,
+ ILGenerator il)
+ {
+ bool found = false;
+ Label projectileDoesntExist = il.DefineLabel();
+
+ FieldInfo thingDefProjectileField = AccessTools.DeclaredField(typeof(ThingDef),
+ "projectile");
+
+ List codes = instructions.ToList();
+ for (int i = 0; i < codes.Count(); ++i)
+ {
+ if (!found && codes[i].LoadsField(thingDefProjectileField))
+ {
+ found = true;
+
+ yield return new CodeInstruction(OpCodes.Dup);
+ yield return new CodeInstruction(OpCodes.Brfalse_S, projectileDoesntExist);
+ yield return codes[i];
+
+ ++i;
+ codes[i].labels.Add(projectileDoesntExist);
+ }
+
+ yield return codes[i];
+ }
+ }
+ }
+}
diff --git a/Source/SRTSCompat/SRTSCompat/SRTSCompat.cs b/Source/SRTSCompat/SRTSCompat/SRTSCompat.cs
new file mode 100644
index 0000000000..e509b77528
--- /dev/null
+++ b/Source/SRTSCompat/SRTSCompat/SRTSCompat.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Diagnostics;
+using System.Linq;
+using System.Reflection;
+using Verse;
+using CombatExtended.Loader;
+using RimWorld;
+using System.Collections.Generic;
+using HarmonyLib;
+using SRTS;
+using UnityEngine;
+
+
+namespace CombatExtended.Compatibility.SRTSCompat
+{
+ [StaticConstructorOnStartup]
+ public class SRTSCompat : IModPart
+ {
+ private static Harmony harmony;
+
+ public Type GetSettingsType()
+ {
+ return null;
+ }
+
+ public IEnumerable GetCompatList()
+ {
+ yield break;
+ }
+
+ public void PostLoad(ModContentPack content, ISettingsCE _)
+ {
+ harmony = new Harmony("CombatExtended.Compatibility.SRTSCompat");
+ harmony.PatchAll(Assembly.GetExecutingAssembly());
+ }
+ }
+}
diff --git a/Source/packages/SRTS-reference.dll b/Source/packages/SRTS-reference.dll
new file mode 100644
index 0000000000..7d0b364775
Binary files /dev/null and b/Source/packages/SRTS-reference.dll differ
diff --git a/SupportedThirdPartyMods.md b/SupportedThirdPartyMods.md
index 601d7e5654..425c17a72f 100644
--- a/SupportedThirdPartyMods.md
+++ b/SupportedThirdPartyMods.md
@@ -412,6 +412,7 @@ Soviet Armory |
Space Worms (Continued) |
Spartan Foundry |
Spidercamp's Horses |
+SRTS Expanded |
Stalingrad – Uniforms |
Steamworld Uniforms |
Star Crafters Armory |
@@ -510,4 +511,4 @@ Xenohumans - Anthromorphs |
Xenohumans Expanded |
Xenoorca Race |
Yet Another Prosthetic Expansion Mod - Core |
-Zombieland |
\ No newline at end of file
+Zombieland |