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 }) {
|
function OutfitKnownGlitchesBadge({ appearance }) {
|
||||||
const glitchMessages = [];
|
const glitchMessages = [];
|
||||||
|
|
||||||
// Look for conflicts between Static pet zones (UCs), and Static items.
|
const { petAppearance, items } = appearance;
|
||||||
const petHasStaticZone = appearance.petAppearance?.layers.some(
|
|
||||||
(l) => l.zone.id === "46"
|
// 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) {
|
const petRestrictedZoneIds = new Set(
|
||||||
for (const item of appearance.items) {
|
petAppearance?.restrictedZones.map((z) => z.id)
|
||||||
const itemHasStaticZone = item.appearance.layers.some(
|
|
||||||
(l) => l.zone.id === "46"
|
|
||||||
);
|
);
|
||||||
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(
|
glitchMessages.push(
|
||||||
<Box key={`static-zone-conflict-for-item-${item.id}`}>
|
<Box key={`uc-conflict-for-item-${item.id}`}>
|
||||||
When you apply a Static-zone item like <i>{item.name}</i> to an
|
<i>{item.name}</i> isn't actually compatible with this special pet.
|
||||||
Unconverted pet, it hides the pet. This is a known bug on
|
We're still showing the old behavior, which is to hide the item.
|
||||||
Neopets.com, so we reproduce it here, too.
|
Fixing this is in our todo list, sorry for the confusing UI!
|
||||||
</Box>
|
</Box>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// Look for items with the OFFICIAL_SVG_IS_INCORRECT glitch.
|
// 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) =>
|
const itemHasOfficialSvgIsIncorrect = item.appearance.layers.some((l) =>
|
||||||
(l.knownGlitches || []).includes("OFFICIAL_SVG_IS_INCORRECT")
|
(l.knownGlitches || []).includes("OFFICIAL_SVG_IS_INCORRECT")
|
||||||
);
|
);
|
||||||
|
@ -321,7 +333,7 @@ function OutfitKnownGlitchesBadge({ appearance }) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for Dyeworks items that aren't converted yet.
|
// 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 itemIsDyeworks = item.name.includes("Dyeworks");
|
||||||
const itemIsConverted = item.appearance.layers.every(layerUsesHTML5);
|
const itemIsConverted = item.appearance.layers.every(layerUsesHTML5);
|
||||||
|
|
||||||
|
|
|
@ -118,33 +118,68 @@ export function getVisibleLayers(petAppearance, itemAppearances) {
|
||||||
|
|
||||||
const validItemAppearances = itemAppearances.filter((a) => a);
|
const validItemAppearances = itemAppearances.filter((a) => a);
|
||||||
|
|
||||||
|
const petLayers = petAppearance.layers.map((l) => ({ ...l, source: "pet" }));
|
||||||
|
|
||||||
const itemLayers = validItemAppearances
|
const itemLayers = validItemAppearances
|
||||||
.map((a) => a.layers)
|
.map((a) => a.layers)
|
||||||
.flat()
|
.flat()
|
||||||
.map((l) => ({ ...l, source: "item" }));
|
.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];
|
let allLayers = [...petLayers, ...itemLayers];
|
||||||
|
|
||||||
const itemRestrictedZoneIds = validItemAppearances
|
const itemRestrictedZoneIds = new Set(
|
||||||
|
validItemAppearances
|
||||||
.map((a) => a.restrictedZones)
|
.map((a) => a.restrictedZones)
|
||||||
.flat()
|
.flat()
|
||||||
.map((z) => z.id);
|
.map((z) => z.id)
|
||||||
const petRestrictedZoneIds = petAppearance.restrictedZones.map((z) => z.id);
|
);
|
||||||
const allRestrictedZoneIds = new Set([
|
const petOccupiedZoneIds = new Set(petLayers.map((l) => l.zone.id));
|
||||||
...itemRestrictedZoneIds,
|
const petRestrictedZoneIds = new Set(
|
||||||
|
petAppearance.restrictedZones.map((z) => z.id)
|
||||||
|
);
|
||||||
|
const petOccupiedOrRestrictedZoneIds = new Set([
|
||||||
|
...petOccupiedZoneIds,
|
||||||
...petRestrictedZoneIds,
|
...petRestrictedZoneIds,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
const visibleLayers = allLayers.filter(
|
const visibleLayers = allLayers.filter((layer) => {
|
||||||
(l) => !allRestrictedZoneIds.has(l.zone.id)
|
// 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);
|
visibleLayers.sort((a, b) => a.zone.depth - b.zone.depth);
|
||||||
|
|
||||||
return visibleLayers;
|
return visibleLayers;
|
||||||
|
|
Loading…
Reference in a new issue