Skip to content

Commit

Permalink
Merge pull request #3355 from ViralReaction/Shield-Testing
Browse files Browse the repository at this point in the history
Add Shield Information to UI
  • Loading branch information
N7Huntsman authored Sep 10, 2024
2 parents ba7d7e6 + 4d13ca0 commit b7547c1
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 1 deletion.
4 changes: 4 additions & 0 deletions Languages/English/Keyed/Keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -172,5 +172,9 @@

<CE_UnpatchedWeapon>This weapon is yet patched for CE, while it will behave in vanilla way as fallback, please contact a patcher for compatibility patches.</CE_UnpatchedWeapon>
<CE_UnpatchedWeaponShort>Not patched for CE</CE_UnpatchedWeaponShort>

<!-- Shield Information -->
<CE_Shield_Coverage>Shield coverage</CE_Shield_Coverage>
<CE_Shield_Coverage_Desc>Body parts protected from ranged and melee attacks by the shield.</CE_Shield_Coverage_Desc>

</LanguageData>
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,12 @@ public bool PartIsCoveredByShield(BodyPartRecord part, Pawn pawn)
}
return false;
}
public static string GetShieldProtectedAreas(BodyDef body, ThingDef thingDef)
{
return (from part in (from x in body.AllParts
where x.depth == BodyPartDepth.Outside && x.groups.Any((BodyPartGroupDef y) => thingDef.GetModExtension<ShieldDefExtension>().shieldCoverage.Contains(y))
select x).Distinct<BodyPartRecord>()
select part.Label).ToCommaList(false, false).CapitalizeFirst();
}
}
}
10 changes: 10 additions & 0 deletions Source/CombatExtended/CombatExtended/Loadouts/ITab_Inventory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using Verse;
using Verse.AI;
using Verse.Sound;
using CombatExtended.HarmonyCE;

namespace CombatExtended
{
Expand Down Expand Up @@ -517,6 +518,7 @@ private void RebuildArmorCache(Dictionary<BodyPartRecord, float> armorCache, Sta
armorCache.Clear();
float naturalArmor = SelPawnForGear.GetStatValue(stat);
List<Apparel> wornApparel = SelPawnForGear.apparel?.WornApparel;
var shield = wornApparel.FirstOrDefault(x => x is Apparel_Shield);
foreach (BodyPartRecord part in SelPawnForGear.RaceProps.body.AllParts)
{
//TODO: 1.5 should be Neck
Expand All @@ -533,6 +535,14 @@ private void RebuildArmorCache(Dictionary<BodyPartRecord, float> armorCache, Sta
}
}
}
if (shield != null)
{
var shieldCoverage = shield.def?.GetModExtension<ShieldDefExtension>()?.PartIsCoveredByShield(part, SelPawnForGear);
if (shieldCoverage == true)
{
armorValue += shield.GetStatValue(stat);
}
}
armorCache[part] = armorValue;
}
}
Expand Down
26 changes: 25 additions & 1 deletion Source/CombatExtended/CombatExtended/Things/Apparel_Shield.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,30 @@ public override bool AllowVerbCast(Verb verb)
ThingWithComps primary = Wearer.equipment?.Primary;
return primary == null || (primary.def.weaponTags?.Contains(OneHandedTag) ?? false);
}

public override IEnumerable<StatDrawEntry> SpecialDisplayStats()
{
foreach (StatDrawEntry statDrawEntry in base.SpecialDisplayStats())
{
yield return statDrawEntry;
}
RoyalTitleDef royalTitleDef = (from t in DefDatabase<FactionDef>.AllDefsListForReading.SelectMany((FactionDef f) => f.RoyalTitlesAwardableInSeniorityOrderForReading)
where t.requiredApparel != null && t.requiredApparel.Any((ApparelRequirement req) => req.ApparelMeetsRequirement(this.def, false))
orderby t.seniority descending
select t).FirstOrDefault<RoyalTitleDef>();
if (royalTitleDef != null)
{
yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "Stat_Thing_Apparel_MaxSatisfiedTitle".Translate(), royalTitleDef.GetLabelCapForBothGenders(), "Stat_Thing_Apparel_MaxSatisfiedTitle_Desc".Translate(), 2752, null, new Dialog_InfoCard.Hyperlink[]
{
new Dialog_InfoCard.Hyperlink(royalTitleDef, -1)
}, false, false);
}
var shieldCoverage = this.def.GetModExtension<ShieldDefExtension>()?.shieldCoverage;
if (shieldCoverage != null)
{
yield return new StatDrawEntry(StatCategoryDefOf.Apparel, "CE_Shield_Coverage".Translate(), ShieldDefExtension.GetShieldProtectedAreas(BodyDefOf.Human, this.def), "CE_Shield_Coverage_Desc".Translate(), 800, null);
}
yield break;
}
public override void DrawWornExtras()
{
if (Wearer == null || !Wearer.Spawned)
Expand Down Expand Up @@ -94,6 +117,7 @@ public override void DrawWornExtras()
Matrix4x4 matrix = default(Matrix4x4);
matrix.SetTRS(vector, Quaternion.AngleAxis(num, Vector3.up), s);
Graphics.DrawMesh(MeshPool.plane10, matrix, mat, 0);

}
}
}
80 changes: 80 additions & 0 deletions Source/CombatExtended/Harmony/Harmony_ThingDef.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
using System.Globalization;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Text;
using HarmonyLib;
using Mono.Cecil.Cil;
using RimWorld;
using Verse;
using Verse.Noise;
Expand Down Expand Up @@ -140,4 +143,81 @@ public static void Postfix(ThingDef __instance)
}
}
}
[HarmonyPatch(typeof(ThingDef), "DescriptionDetailed", MethodType.Getter)]

internal static class ThingDef_DescriptionDetailed
{
private static StringBuilder AddShieldCover(ThingDef thingDef, StringBuilder stringBuilder)
{
if (thingDef.GetModExtension<ShieldDefExtension>()?.shieldCoverage != null)
{
stringBuilder.Append(string.Format("{0}: {1}", "CE_Shield_Coverage".Translate(), ShieldDefExtension.GetShieldProtectedAreas(BodyDefOf.Human, thingDef)));
}
else
{
stringBuilder.Append(string.Format("{0}: {1}", "Covers".Translate(), thingDef.apparel.GetCoveredOuterPartsString(BodyDefOf.Human)));
}
return stringBuilder;
}
internal static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions,
ILGenerator generator)
{
var code = new List<CodeInstruction>(instructions);
int startIndex = -1;
int endIndex = -1;
bool foundCovers = false;

for (int i = 0; i < code.Count; i++)
{
if (code[i].opcode == OpCodes.Ldloc_0)
{
startIndex = i;

// Search for the next Pop, and check if "Covers" is in between
for (int j = i + 1; j < code.Count; j++)
{
if (code[j].opcode == OpCodes.Ldstr && code[j].operand as string == "Covers")
{
foundCovers = true;
}

if (code[j].opcode == OpCodes.Pop)
{
if (foundCovers)
{
endIndex = j;
break;
}
else
{
// If no "Covers" was found, reset startIndex and move to the next possible sequence
startIndex = -1;
break;
}
}
}
}

if (endIndex > -1)
{
break;
}
}

// Remove the code between startIndex and endIndex if a valid range was found
if (startIndex > -1 && endIndex > -1)
{
code[startIndex].opcode = OpCodes.Nop;
//code[endIndex].opcode = OpCodes.Nop;
code.RemoveRange(startIndex + 1, endIndex - startIndex - 1);
code.Insert(startIndex + 1, new CodeInstruction(OpCodes.Ldarg_0));
code.Insert(startIndex + 2, new CodeInstruction(OpCodes.Ldloc_0));
code.Insert(startIndex + 3, new CodeInstruction(OpCodes.Call, AccessTools.Method(typeof(ThingDef_DescriptionDetailed), "AddShieldCover", null, null)));
}
foreach (var c in code)
{
yield return c;
}
}
}
}

0 comments on commit b7547c1

Please sign in to comment.