FurnitureFilter.ts 7.4 Ko
Télécharger le fichier
import { GetSessionDataManager, IFurnitureData } from '@octane/renderer';
import { LocalizeText } from '../utils';
import { FurniCategory } from './FurniCategory';
import { GroupItem } from './GroupItem';
export const FURNI_MAIN_FILTER = {
ALL: 'all',
FLOOR: 'floor_items',
WALL: 'wall_items',
ROOM_LAYOUT: 'room_layout'
} as const;
export type FurniMainFilter = (typeof FURNI_MAIN_FILTER)[keyof typeof FURNI_MAIN_FILTER];
export const FURNI_TYPE_OPTIONS: Record<FurniMainFilter, string[]> = {
all: ['any', 'sittable', 'layable', 'tiles_or_rugs', 'ltd', 'wired', 'credit_furni', 'clothes', 'pet_food', 'tradable', 'non_tradable', 'recyclable'],
floor_items: [
'any',
'sittable',
'layable',
'tiles_or_rugs',
'ltd',
'wired',
'credit_furni',
'clothes',
'pet_food',
'tradable',
'non_tradable',
'recyclable'
],
wall_items: ['any', 'windows', 'dimmers', 'stickies', 'paintings', 'tradable', 'non_tradable', 'recyclable'],
room_layout: ['any', 'floors', 'wallpapers', 'landscape']
};
export const furniMainFilterKey = (id: string) => `inventory.furni.filter.main.${id}`;
export const furniTypeFilterKey = (id: string) => `inventory.furni.filter.type.${id}`;
const isRoomLayoutCategory = (category: number) =>
category === FurniCategory.WALL_PAPER || category === FurniCategory.FLOOR || category === FurniCategory.LANDSCAPE;
const getFurniData = (item: GroupItem): IFurnitureData => {
const session = GetSessionDataManager();
if (!session || item.type < 0) return null;
return item.isWallItem ? session.getWallItemData(item.type) : session.getFloorItemData(item.type);
};
const matchesMainFilter = (item: GroupItem, main: FurniMainFilter): boolean => {
switch (main) {
case FURNI_MAIN_FILTER.FLOOR:
return !item.isWallItem;
case FURNI_MAIN_FILTER.WALL:
return item.isWallItem && !isRoomLayoutCategory(item.category);
case FURNI_MAIN_FILTER.ROOM_LAYOUT:
return isRoomLayoutCategory(item.category);
default:
return true;
}
};
const matchesTypeFilter = (item: GroupItem, typeId: string): boolean => {
if (!typeId || typeId === 'any') return true;
const last = item.getLastItem();
const data = getFurniData(item);
const className = data?.className ?? '';
const category = data?.category ?? '';
const furniLine = data?.furniLine ?? '';
switch (typeId) {
case 'sittable':
return !!data?.canSitOn;
case 'layable':
return !!data?.canLayOn;
case 'tiles_or_rugs':
if (!data || className.startsWith('tile_walkmagic') || className === 'hole' || !data.canPutStuffOn) return false;
if (category === 'rug' || category === 'floor' || className.startsWith('carpet')) return true;
// tileSizeZ is not AIR's height: legacy Renderer loaders set it to 0.
return data.height !== undefined && data.height <= 0.2 && data.canStandOn && data.tileSizeX > 1 && data.tileSizeY > 1;
case 'ltd':
return (last?.stuffData?.uniqueNumber ?? 0) > 0;
case 'wired':
return className.startsWith('wf_') || category.startsWith('wired_');
case 'credit_furni':
return item.category === FurniCategory.CREDIT_FURNI || className.startsWith('CF_');
case 'clothes':
return item.category === FurniCategory.FIGURE_PURCHASABLE_SET;
case 'pet_food':
return className.startsWith('petfood') || furniLine === 'pet_food';
case 'tradable':
return data?.tradeable ?? !!last?.isTradable;
case 'non_tradable':
return data?.tradeable !== undefined ? !data.tradeable : !!last && !last.isTradable;
case 'recyclable':
return !!last?.recyclable;
case 'windows':
return className.startsWith('window_') || furniLine === 'windows' || category === 'window';
case 'dimmers':
return className.startsWith('dimmer_') || category === 'dimmer' || furniLine === 'dimmers';
case 'stickies':
return item.category === FurniCategory.POST_IT;
case 'paintings':
return className.startsWith('diamond_painting');
case 'floors':
return item.category === FurniCategory.FLOOR;
case 'wallpapers':
return item.category === FurniCategory.WALL_PAPER;
case 'landscape':
return item.category === FurniCategory.LANDSCAPE;
default:
return true;
}
};
const getDescription = (item: GroupItem): string => {
if (item.description) return item.description;
let key: string;
switch (item.category) {
case FurniCategory.WALL_PAPER:
key = 'inventory.furni.item.wallpaper.desc';
break;
case FurniCategory.FLOOR:
key = 'inventory.furni.item.floor.desc';
break;
case FurniCategory.LANDSCAPE:
key = 'inventory.furni.item.landscape.desc';
break;
case FurniCategory.POSTER:
key = `poster_${item.getLastItem()?.stuffData?.getLegacyString()}_desc`;
break;
case FurniCategory.TRAX_SONG:
// AIR obtains song creator from music-controller metadata, which is
// not exposed by Octane GroupItem yet.
return '';
default:
key = `${item.isWallItem ? 'wallItem' : 'roomItem'}.desc.${item.type}`;
}
const localized = LocalizeText(key);
return localized === key ? (getFurniData(item)?.description ?? '') : localized;
};
export const filterFurnitureGroupItems = (groupItems: GroupItem[], searchValue: string, mainFilter: FurniMainFilter, typeFilter: string): GroupItem[] => {
const comparison = searchValue.toLowerCase();
return groupItems.filter((item) => {
if (!matchesMainFilter(item, mainFilter)) return false;
if (!matchesTypeFilter(item, typeFilter)) return false;
if (!comparison.length) return true;
const name = item.name ?? '';
const description = getDescription(item);
const chestName = item.stuffData?.chestName ?? '';
return [name, description, chestName].some((value) => value.toLowerCase().includes(comparison));
});
};
/** The three furniture sections of the official inventory: owned furni, collectibles and rentables. */
export type FurnitureSection = 'furni' | 'collectibles' | 'rentables';
const isRentableGroup = (item: GroupItem): boolean => !!item.getLastItem()?.rentable;
const isCollectibleGroup = (item: GroupItem): boolean => !isRentableGroup(item) && (item.getLastItem()?.stuffData?.uniqueNumber ?? 0) > 0;
/**
* What a furniture section holds: a rented item is only a rentable, a numbered one only a collectible.
* With `numberedInFurni` (the hotel runs collectibles, whose tab shows the collectibles themselves) the
* numbered furni stay in the furni section, as in the official inventory.
*/
export const inFurnitureSection = (groupItems: GroupItem[], section: FurnitureSection, numberedInFurni: boolean = false): GroupItem[] => {
switch (section) {
case 'rentables':
return groupItems.filter(isRentableGroup);
case 'collectibles':
return groupItems.filter(isCollectibleGroup);
default:
return groupItems.filter((item) => !isRentableGroup(item) && (numberedInFurni || !isCollectibleGroup(item)));
}
};
