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

Add Shield Information to UI #3355

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
10 changes: 7 additions & 3 deletions Languages/English/Keyed/Keys.xml
Original file line number Diff line number Diff line change
Expand Up @@ -122,10 +122,10 @@
<CE_degrees>&#176;</CE_degrees>
<CE_meters>m</CE_meters>
<CE_WeaponPenetrationFactor>Weapon penetration factor</CE_WeaponPenetrationFactor>
<CE_WeaponPenetrationSkillFactor>Skill factor</CE_WeaponPenetrationSkillFactor>
<CE_WeaponPenetrationOtherFactors>Other factors</CE_WeaponPenetrationOtherFactors>
<CE_WeaponPenetrationSkillFactor>Skill factor</CE_WeaponPenetrationSkillFactor>
<CE_WeaponPenetrationOtherFactors>Other factors</CE_WeaponPenetrationOtherFactors>
<CE_AdjustedForWeapon>Adjusted for weapon</CE_AdjustedForWeapon>
<CE_RangedQualityMultiplier>Penetration quality factor</CE_RangedQualityMultiplier>
<CE_RangedQualityMultiplier>Penetration quality factor</CE_RangedQualityMultiplier>
<CE_DPS>Damage per second</CE_DPS>
<CE_DamageVariation>Damage variation</CE_DamageVariation>
<CE_FinalAverageDamage>Final average damage</CE_FinalAverageDamage>
Expand Down Expand Up @@ -161,5 +161,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)
{
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;
}
}
}
}
Loading