2022-01-15 07:19:54 +00:00
|
|
|
|
using AlienRace;
|
2023-01-01 23:11:05 +00:00
|
|
|
|
using AlienRace.ExtendedGraphics;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
using HarmonyLib;
|
|
|
|
|
using RimWorld;
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
using System.Linq;
|
|
|
|
|
using Verse;
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// The RevealingApparel mod extension allows us to add information to apparel that tells us if wearing an apparel item
|
|
|
|
|
// should also cover the body parts introduced by RNW. This way mod authors can make an apparel item that covers a pawn's
|
|
|
|
|
// torso but still draws their breasts or genitals.
|
2022-01-15 07:19:54 +00:00
|
|
|
|
namespace RevealingApparel
|
|
|
|
|
{
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// This is the mod extension that people will use to add revealing information to their apparel defs.
|
2022-01-15 07:19:54 +00:00
|
|
|
|
public class ApparelRevealingExtension : DefModExtension
|
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// A list of RevealingExtensionEntry items, which describe what body parts are revealed when a pawn is wearing this apparel item
|
2022-01-15 07:19:54 +00:00
|
|
|
|
public List<RevealingExtensionEntry> revealingBodyPartEntries = new List<RevealingExtensionEntry>();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// The entry class that describes what body parts are revealed
|
2022-01-15 07:19:54 +00:00
|
|
|
|
public class RevealingExtensionEntry
|
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// The path to the body part that is revealed.
|
|
|
|
|
// Examples include "Breasts/FeaturelessLeft" or "Genitals/FeaturelessCrotch"
|
|
|
|
|
public string revealingPath;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// A list of pawn body types this entry applies to.
|
|
|
|
|
// Examples include "Female" or "Thin" or "Hulk"
|
2022-01-15 07:19:54 +00:00
|
|
|
|
public List<BodyTypeDef> revealingBodyTypes = new List<BodyTypeDef>();
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// We are going to postfix patch the VisibleUnderApparelOf check in HAR so we can make body parts visible if all of the apparel
|
|
|
|
|
// covering it is marked as revealing
|
|
|
|
|
[HarmonyPatch(typeof(AlienPartGenerator.BodyAddon), "VisibleUnderApparelOf")]
|
|
|
|
|
class HarmonyPatch_RevealingApparel_VisibleUnderApparelOf
|
2022-01-15 07:19:54 +00:00
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
public static Pawn GetPawnFromWrapped(ExtendedGraphicsPawnWrapper pawn)
|
2022-01-15 07:19:54 +00:00
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// The pawn wrapper doesn't expose the original Pawn as a public field, so we need to use reflection
|
|
|
|
|
// to pull it out.
|
|
|
|
|
return Traverse.Create(pawn).Property("WrappedPawn").GetValue<Pawn>();
|
2022-01-15 07:19:54 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
public static IEnumerable<Apparel> GetApparelCoveringPart(Pawn pawn, AlienPartGenerator.BodyAddon bodyAddon)
|
|
|
|
|
{
|
|
|
|
|
// Get a list of all of the apparel worn by this pawn
|
|
|
|
|
return pawn.apparel?.WornApparel?.Where(
|
|
|
|
|
// Where any of the body part groups this apparel covers
|
|
|
|
|
apparel => apparel.def.apparel.bodyPartGroups.Any(
|
|
|
|
|
// Hide the passed body addon
|
|
|
|
|
bodyPartGroup => bodyAddon.hiddenUnderApparelFor.Contains(bodyPartGroup)));
|
|
|
|
|
}
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
public static bool IsApparelRevealingBodyPart(Apparel apparel, AlienPartGenerator.BodyAddon bodyAddon, BodyTypeDef bodyType)
|
2022-01-15 07:19:54 +00:00
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Get the revealing entries for this apparel item
|
|
|
|
|
var revealingExtension = apparel.def.GetModExtension<ApparelRevealingExtension>();
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// And return if one of these entries matches the body part for this pawn body type
|
|
|
|
|
return revealingExtension?.revealingBodyPartEntries.Any((entry) =>
|
2022-01-15 07:19:54 +00:00
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Does this entry reveal the body part we are considering
|
|
|
|
|
bool entryMatchesBodyPart = entry.revealingPath?.Contains(bodyAddon.GetPath()) ?? false;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Does this entry apply to the pawn's body shape
|
|
|
|
|
bool entryMatchesPawnBody = entry.revealingBodyTypes?.Contains(bodyType) ?? false;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// If this entry matches the part and applies to the pawn body type, then this apparel reveals this body part
|
|
|
|
|
return entryMatchesBodyPart && entryMatchesPawnBody;
|
|
|
|
|
}) ?? false; // If there are no revealing body part entries, then this apparel covers this body part
|
|
|
|
|
}
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
public static bool Postfix(bool __result, AlienPartGenerator.BodyAddon __instance, ExtendedGraphicsPawnWrapper pawn)
|
|
|
|
|
{
|
|
|
|
|
// If the original method returned false, we might still show it based on the revealing apparel entries
|
|
|
|
|
if (__result == false)
|
2022-01-15 07:19:54 +00:00
|
|
|
|
{
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Grab the underlying pawn from the wrapped version we were passed
|
|
|
|
|
var myPawn = GetPawnFromWrapped(pawn);
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Reference the pawn body type. We will need this to know if revealing body part entries apply to this pawn
|
|
|
|
|
var bodyType = myPawn.story.bodyType;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Get a list of all of the apparel worn by this pawn that covers this body part
|
|
|
|
|
var apparelCoveringPartList = GetApparelCoveringPart(myPawn, __instance);
|
2022-01-15 07:19:54 +00:00
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// If no apparel is covering this part OR they are all revealing, then reveal this body part
|
|
|
|
|
if (apparelCoveringPartList.Count() == 0 ||
|
|
|
|
|
apparelCoveringPartList.All(apparel => IsApparelRevealingBodyPart(apparel, __instance, bodyType))) {
|
|
|
|
|
return true;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-01-01 23:11:05 +00:00
|
|
|
|
// Else, return the original result
|
|
|
|
|
return __result;
|
2022-01-15 07:19:54 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|