The NEW UC rule is that non-body-specific is okay!
This commit is contained in:
parent
36b0cb75e5
commit
927401fc92
2 changed files with 82 additions and 35 deletions
|
@ -283,29 +283,41 @@ function OutfitHTML5Badge({ appearance }) {
|
|||
function OutfitKnownGlitchesBadge({ appearance }) {
|
||||
const glitchMessages = [];
|
||||
|
||||
// Look for conflicts between Static pet zones (UCs), and Static items.
|
||||
const petHasStaticZone = appearance.petAppearance?.layers.some(
|
||||
(l) => l.zone.id === "46"
|
||||
const { petAppearance, items } = appearance;
|
||||
|
||||
// Look for UC/Invisible/etc incompatibilities that we hid, that we should
|
||||
// just mark Incompatible someday instead.
|
||||
//
|
||||
// HACK: Most of this logic is copy-pasted from `useOutfitAppearance`.
|
||||
const petOccupiedZoneIds = new Set(
|
||||
petAppearance?.layers.map((l) => l.zone.id)
|
||||
);
|
||||
if (petHasStaticZone) {
|
||||
for (const item of appearance.items) {
|
||||
const itemHasStaticZone = item.appearance.layers.some(
|
||||
(l) => l.zone.id === "46"
|
||||
const petRestrictedZoneIds = new Set(
|
||||
petAppearance?.restrictedZones.map((z) => z.id)
|
||||
);
|
||||
if (itemHasStaticZone) {
|
||||
const petOccupiedOrRestrictedZoneIds = new Set([
|
||||
...petOccupiedZoneIds,
|
||||
...petRestrictedZoneIds,
|
||||
]);
|
||||
for (const item of items) {
|
||||
const itemHasZoneRestrictedByPet = item.appearance.layers.some(
|
||||
(layer) =>
|
||||
layer.bodyId !== "0" &&
|
||||
petOccupiedOrRestrictedZoneIds.has(layer.zone.id)
|
||||
);
|
||||
if (itemHasZoneRestrictedByPet) {
|
||||
glitchMessages.push(
|
||||
<Box key={`static-zone-conflict-for-item-${item.id}`}>
|
||||
When you apply a Static-zone item like <i>{item.name}</i> to an
|
||||
Unconverted pet, it hides the pet. This is a known bug on
|
||||
Neopets.com, so we reproduce it here, too.
|
||||
<Box key={`uc-conflict-for-item-${item.id}`}>
|
||||
<i>{item.name}</i> isn't actually compatible with this special pet.
|
||||
We're still showing the old behavior, which is to hide the item.
|
||||
Fixing this is in our todo list, sorry for the confusing UI!
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Look for items with the OFFICIAL_SVG_IS_INCORRECT glitch.
|
||||
for (const item of appearance.items) {
|
||||
for (const item of items) {
|
||||
const itemHasOfficialSvgIsIncorrect = item.appearance.layers.some((l) =>
|
||||
(l.knownGlitches || []).includes("OFFICIAL_SVG_IS_INCORRECT")
|
||||
);
|
||||
|
@ -321,7 +333,7 @@ function OutfitKnownGlitchesBadge({ appearance }) {
|
|||
}
|
||||
|
||||
// Look for Dyeworks items that aren't converted yet.
|
||||
for (const item of appearance.items) {
|
||||
for (const item of items) {
|
||||
const itemIsDyeworks = item.name.includes("Dyeworks");
|
||||
const itemIsConverted = item.appearance.layers.every(layerUsesHTML5);
|
||||
|
||||
|
|
|
@ -118,33 +118,68 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
|
|||
|
||||
const validItemAppearances = itemAppearances.filter((a) => a);
|
||||
|
||||
const petLayers = petAppearance.layers.map((l) => ({ ...l, source: "pet" }));
|
||||
|
||||
const itemLayers = validItemAppearances
|
||||
.map((a) => a.layers)
|
||||
.flat()
|
||||
.map((l) => ({ ...l, source: "item" }));
|
||||
const itemOccupiedZoneIds = new Set(itemLayers.map((l) => l.zone.id));
|
||||
|
||||
const petLayers = petAppearance.layers
|
||||
.map((l) => ({ ...l, source: "pet" }))
|
||||
// Copying weird Neopets.com behavior: if an item occupies a zone that the
|
||||
// pet also occupies, the pet's corresponding zone is hidden.
|
||||
.filter((l) => !itemOccupiedZoneIds.has(l.zone.id));
|
||||
|
||||
let allLayers = [...petLayers, ...itemLayers];
|
||||
|
||||
const itemRestrictedZoneIds = validItemAppearances
|
||||
const itemRestrictedZoneIds = new Set(
|
||||
validItemAppearances
|
||||
.map((a) => a.restrictedZones)
|
||||
.flat()
|
||||
.map((z) => z.id);
|
||||
const petRestrictedZoneIds = petAppearance.restrictedZones.map((z) => z.id);
|
||||
const allRestrictedZoneIds = new Set([
|
||||
...itemRestrictedZoneIds,
|
||||
.map((z) => z.id)
|
||||
);
|
||||
const petOccupiedZoneIds = new Set(petLayers.map((l) => l.zone.id));
|
||||
const petRestrictedZoneIds = new Set(
|
||||
petAppearance.restrictedZones.map((z) => z.id)
|
||||
);
|
||||
const petOccupiedOrRestrictedZoneIds = new Set([
|
||||
...petOccupiedZoneIds,
|
||||
...petRestrictedZoneIds,
|
||||
]);
|
||||
|
||||
const visibleLayers = allLayers.filter(
|
||||
(l) => !allRestrictedZoneIds.has(l.zone.id)
|
||||
);
|
||||
const visibleLayers = allLayers.filter((layer) => {
|
||||
// When an item restricts a zone, it hides pet layers of the same zone.
|
||||
// We use this to e.g. make a hat hide a hair ruff.
|
||||
//
|
||||
// NOTE: Items' restricted layers also affect what items you can wear at
|
||||
// the same time. We don't enforce anything about that here, and
|
||||
// instead assume that the input by this point is valid!
|
||||
if (layer.source === "pet" && itemRestrictedZoneIds.has(layer.zone.id)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// When a pet appearance restricts or occupies a zone, it makes items
|
||||
// that occupy the zone incompatible, but *only* if the item is
|
||||
// body-specific. We use this to disallow UCs from wearing certain
|
||||
// body-specific Biology Effects, Statics, etc, while still allowing
|
||||
// non-body-specific items in those zones! (I think this happens for some
|
||||
// Invisible pet stuff, too?)
|
||||
//
|
||||
// NOTE: This can result in both pet layers and items occupying the same
|
||||
// zone, like Static! That's correct, and the item layer should be
|
||||
// on top! (Here, we implement it by placing item layers second in
|
||||
// the list, and depending on JS sort stability, and *then* depending
|
||||
// on the UI to respect that ordering when rendering them by depth.
|
||||
// Not great! 😅)
|
||||
//
|
||||
// TODO: Hiding the layer is the *old* behavior. Move this way deeper in
|
||||
// the code to prevent these items from showing up in the first
|
||||
// place!
|
||||
if (
|
||||
layer.source === "item" &&
|
||||
layer.bodyId !== "0" &&
|
||||
petOccupiedOrRestrictedZoneIds.has(layer.zone.id)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
visibleLayers.sort((a, b) => a.zone.depth - b.zone.depth);
|
||||
|
||||
return visibleLayers;
|
||||
|
|
Loading…
Reference in a new issue