Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes for siege mortar ammo #3169

Merged
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Biotech/Patches/DamageDefs/Damages_Misc.xml
Original file line number Diff line number Diff line change
Expand Up @@ -36,4 +36,15 @@
</value>
</Operation>

<!-- ========== ToxGas ========== -->

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="ToxGas"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I honestly think this is probably something we'd prefer to add to the ammo item, rather than the DamageDef itself--that leaves us finer control over what does or doesn't spawn for mortar shells dropped to sieges. Thoughts?

Copy link
Contributor Author

@Rhinous Rhinous Jun 7, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't really like how currently we can't control it per shell, was originally done this way to stay similar to the old/vanilla method of just checking damage but it's definitely gotten bloated/overcomplicated. What do you think about scrapping the damage/harmshealth checks entirely and instead adding something like SpawnAsSiegeAmmo to the AmmoDef class? That way we can just blacklist shells we don't want since I think default behaviour should be to include them

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think an easy true/false we can just assign to each shell as an override is probably our easiest way to address edge cases. Leave the more straight-forward checks in the code to filter out shells that obviously aren't suitable for siege, but we'll just use xml to address any outliers as necessary. Otherwise, we end up with a hideous, expensive string of checks that still will find a way to let some strange shells spawn when they shouldn't.

<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

</Patch>
64 changes: 64 additions & 0 deletions ModPatches/BiologicalWarfare/Patches/Patches.xml
Original file line number Diff line number Diff line change
Expand Up @@ -289,4 +289,68 @@
defName="USH_SleepingSicknessGrenadeLauncher" or
defName="USH_SleepingSicknessGrenadeBullet"]</xpath>
</Operation>

<!-- ========== Patch DamageDefs to allow sieges to use mortars ========== -->
<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_FleshBreakerDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_FluDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_MalariaDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_NecroaDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_PlagueDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_ScariaDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>

<Operation Class="PatchOperationAddModExtension">
<xpath>Defs/DamageDef[defName="USH_SleepingSicknessDamage"]</xpath>
<value>
<li Class="CombatExtended.DamageDefExtensionCE">
<isHarmful>true</isHarmful>
</li>
</value>
</Operation>
</Patch>
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,6 @@ public class DamageDefExtensionCE : DefModExtension
public bool harmOnlyOutsideLayers = false;
public bool isAmbientDamage = false;
public float worldDamageMultiplier = -1f;
public bool isHarmful = false;
}
}
76 changes: 74 additions & 2 deletions Source/CombatExtended/Harmony/Harmony_LordToil_Siege.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using HarmonyLib;
using RimWorld;
using Verse;
Expand All @@ -11,8 +13,78 @@ internal static class Harmony_LordToil_Siege
{
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions)
{
return instructions.MethodReplacer(typeof(ThingDef).GetMethod("get_IsShell"),
typeof(AmmoUtility).GetMethod(nameof(AmmoUtility.IsShell), BindingFlags.Public | BindingFlags.Static));
var codes = new List<CodeInstruction>(instructions);
var methodCustomCondition = typeof(Harmony_LordToil_Siege).GetMethod(nameof(CustomCondition), BindingFlags.Static | BindingFlags.Public);
var startIndex = -1;
var endIndex = -1;
MethodInfo targetMethod = AccessTools.Method(typeof(ThingDef), "get_IsShell"); // Start of the if condition
FieldInfo targetField = AccessTools.Field(typeof(DamageDef), "harmsHealth"); // End of the if condition
for (int i = 0; i < codes.Count; i++)
{
if (startIndex == -1)
{
// Find the start of the if statement
if (codes[i].opcode == OpCodes.Callvirt && codes[i].Calls(targetMethod))
{
startIndex = i - 1; // We want to edit -1 instruction from the call of IsShell
}
}
else if (codes[i].opcode == OpCodes.Ldfld && codes[i].LoadsField(targetField))
{
endIndex = i;
}
}
if (startIndex == -1 || endIndex == -1)
{
Log.Error("CombatExtended :: Harmony_LordToil_Siege couldn't find code block for patching");
return codes; // Don't modify as we couldn't find the original code block
}
else
{
codes[startIndex] = new CodeInstruction(OpCodes.Call, methodCustomCondition); // Call the new method for evaluation
codes.RemoveRange(startIndex + 1, endIndex - startIndex); // Remove the default code
return codes;
}
}

public static bool CustomCondition(Thing thing)
{
// Ensure damage check is the same here as from CombatExtended.HarmonyCE.Harmony_TurretGunUtility
var ammoDef = thing.def as AmmoDef;
if (ammoDef == null)
{
return false;
}
// Ignore all non-shell defs.
if (ammoDef == null || !AmmoUtility.IsShell(ammoDef))
{
return false;
}

// Get the explosive damage def.
var explosiveDamageDef = ammoDef.GetCompProperties<CompProperties_ExplosiveCE>()?.explosiveDamageType ?? ammoDef.GetCompProperties<CompProperties_Explosive>()?.explosiveDamageType;

// Get the projectile damage def via the mortar ammo set.
var projectileDamageDef = ammoDef.projectile?.damageDef ?? CE_AmmoSetDefOf.AmmoSet_81mmMortarShell.ammoTypes.FirstOrDefault(t => t.ammo == ammoDef)?.projectile?.projectile?.damageDef;

// Ignore shells that don't have damage defs.
if (explosiveDamageDef == null && projectileDamageDef == null)
{
return false;
}

// Get the number of fragments
var fragments = ammoDef.GetCompProperties<CompProperties_Fragments>()?.fragments.Count;

// Get patched harmful damage for modded/toxic shells
var harmful = projectileDamageDef?.GetModExtension<DamageDefExtensionCE>()?.isHarmful ?? false;

// Check if shell harms health.
if ((explosiveDamageDef == null || !explosiveDamageDef.harmsHealth) && (projectileDamageDef == null || !projectileDamageDef.harmsHealth) && (fragments == null || fragments < 1) && !harmful)
{
return false;
}
return true;
}
}
}
9 changes: 8 additions & 1 deletion Source/CombatExtended/Harmony/Harmony_TurretGunUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public static class Harmony_TurretGunUtility
const string className = "DisplayClass";
const string methodName = "<TryFindRandomShellDef>";

// This should be kept up to date with the check in CombatExtended.HarmonyCE.Harmony_LordToil_Siege
public static void Postfix(object __instance, ThingDef x, ref bool __result, bool ___allowEMP, float ___maxMarketValue, bool ___mustHarmHealth)
{
// Ignore already true results.
Expand Down Expand Up @@ -60,8 +61,14 @@ public static void Postfix(object __instance, ThingDef x, ref bool __result, boo
return;
}

// Get the number of fragments
var fragments = ammoDef.GetCompProperties<CompProperties_Fragments>()?.fragments.Count;

// Get patched harmful damage for modded/toxic shells
var harmful = projectileDamageDef?.GetModExtension<DamageDefExtensionCE>()?.isHarmful ?? false;

// Check if shell harms health.
if (___mustHarmHealth && explosiveDamageDef != null && !explosiveDamageDef.harmsHealth && projectileDamageDef != null && !projectileDamageDef.harmsHealth)
if (___mustHarmHealth && (explosiveDamageDef == null || !explosiveDamageDef.harmsHealth) && (projectileDamageDef == null || !projectileDamageDef.harmsHealth) && (fragments == null || fragments < 1) && !harmful)
{
return;
}
Expand Down
Loading