Skip to content
This repository was archived by the owner on Dec 22, 2025. It is now read-only.

Commit 672ac6e

Browse files
committed
Fix order of equipments to be same as the game
1 parent 8bebbd4 commit 672ac6e

File tree

3 files changed

+113
-5
lines changed

3 files changed

+113
-5
lines changed

common/sortUtils.ts

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/* eslint-disable valid-jsdoc */
12
import {isNumber} from 'common/checkVariableTypeUtil';
23

34
export enum SortingOrder{
@@ -22,4 +23,82 @@ export const sortTwoUnknownValues = (valueA: unknown, valueB: unknown,
2223
}
2324
};
2425

26+
type Comparator<Item> = (a: Item, b: Item) => number;
2527

28+
const Ordering = {
29+
/** They are equals. */
30+
Equal: 0,
31+
/** The first value is sorted after the second. */
32+
First: +1,
33+
/** The second value is sorted after the first. */
34+
Second: -1,
35+
} as const;
36+
37+
const isNully = (x: unknown): x is null | undefined => {
38+
return x === null || x === undefined;
39+
};
40+
41+
/**
42+
* @param keySelector
43+
* A mapping function to extract key from an array element.
44+
* Note that this function can return null or undefined,
45+
* but these values are treated as greater than other values.
46+
* @param comparatorFn
47+
* This comparator functions are applied in order, starting with the first,
48+
* and if the previous returns 0, the next is applied.
49+
* When all functions s return 0, it means the two elements are equal.
50+
* @return a comparator function.
51+
*/
52+
export const buildComparator = <Item, Key>(
53+
keySelector: (item: Item) => (Key | null | undefined),
54+
...comparatorFn: Comparator<Key>[]
55+
): Comparator<Item> => {
56+
return (firstItem, secondItem) => {
57+
if (firstItem === secondItem) return Ordering.Equal;
58+
const first = keySelector(firstItem);
59+
const second = keySelector(secondItem);
60+
if (first === second) return Ordering.Equal;
61+
62+
if (isNully(first) || isNully(second)) {
63+
return (first === second) ? Ordering.Equal :
64+
isNully(first) ? Ordering.First :
65+
isNully(second) ? Ordering.Second :
66+
'unreachable' as never;
67+
}
68+
69+
for (const comparator of comparatorFn) {
70+
const ordering = comparator(first, second);
71+
if (ordering != Ordering.Equal) return ordering;
72+
}
73+
74+
return Ordering.Equal;
75+
};
76+
};
77+
78+
const numberAscending: Comparator<number> = (a, b) => a - b;
79+
const numberDescending: Comparator<number> = (a, b) => b - a;
80+
const stringAscending: Comparator<string> = (a, b) => a.localeCompare(b);
81+
const stringDescending: Comparator<string> = (a, b) => b.localeCompare(a);
82+
const numericStringAscending = buildComparator(parseFloat, numberAscending);
83+
const numericStringDescending = buildComparator(parseFloat, numberDescending);
84+
export const Comparators = {
85+
numberAscending, numberDescending,
86+
stringAscending, stringDescending,
87+
numericStringAscending, numericStringDescending,
88+
} as const;
89+
90+
export const buildArrayIndexComparator = <Item>(
91+
array: readonly Item[],
92+
order: SortingOrder = SortingOrder.Ascending,
93+
) => {
94+
const comparator = order === SortingOrder.Ascending ?
95+
Comparators.numberAscending :
96+
Comparators.numberDescending;
97+
return buildComparator<Item, number>(
98+
(item) => {
99+
const index = array.indexOf(item);
100+
return index >= 0 ? index : null;
101+
},
102+
comparator,
103+
);
104+
};

components/calculationInput/equipments/inventory/AddToInventoryDialog.tsx

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,23 @@
11
import styles from './AddToInventoryDialog.module.scss';
2-
import {Button, Dialog, DialogActions, DialogContent, DialogTitle, useMediaQuery, useTheme} from '@mui/material';
2+
import {
3+
Button, Dialog, DialogActions, DialogContent, DialogTitle,
4+
useMediaQuery, useTheme,
5+
} from '@mui/material';
36
import React, {useEffect, useMemo, useReducer} from 'react';
47
import {useTranslation} from 'next-i18next';
58
import {useForm} from 'react-hook-form';
6-
import {DropPieceIdWithProbAndCount, EquipmentsById} from 'components/calculationInput/PiecesCalculationCommonTypes';
9+
import {
10+
DropPieceIdWithProbAndCount, EquipmentsById,
11+
} from 'components/calculationInput/PiecesCalculationCommonTypes';
712
import {InventoryForm} from './InventoryUpdateDialog';
813
import ObtainedPieceBox from './ObtainedPieceBox';
914
import {useStore} from 'stores/WizStore';
1015
import {PieceState} from './PiecesInventory';
16+
import {
17+
Comparators, SortingOrder,
18+
buildArrayIndexComparator, buildComparator,
19+
} from 'common/sortUtils';
20+
import {EquipmentCategories} from 'model/Equipment';
1121

1222
const AddToInventoryDialog = ({
1323
open,
@@ -36,9 +46,21 @@ const AddToInventoryDialog = ({
3646

3747
const pieceIds = useMemo(() => drops.map((drop) => drop.id), [drops]);
3848
const pieces = useMemo(() => {
49+
// 20-3: Necklace, Watch, Bag
50+
// 20-4: Watch, Charm, Badge
51+
// 13-1: Shoes, Gloves, Hat
52+
// descending tier -> descending category order?
3953
return Array.from(piecesState.values())
40-
.filter((state) => pieceIds.includes(state.pieceId) && state.needCount > 0);
41-
}, [piecesState, pieceIds]);
54+
.filter((state) => pieceIds.includes(state.pieceId) && state.needCount > 0)
55+
.toSorted(buildComparator(
56+
(piece) => equipById.get(piece.pieceId),
57+
buildComparator((e) => e.tier, Comparators.numberDescending),
58+
buildComparator((e) => e.category, buildArrayIndexComparator(
59+
EquipmentCategories,
60+
SortingOrder.Descending
61+
)),
62+
));
63+
}, [piecesState, pieceIds, equipById]);
4264
const defaultValues = useMemo(() => {
4365
return pieces.reduce<InventoryForm>((acc, piece) => {
4466
acc[piece.pieceId] = '';

model/Equipment.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,16 @@ export enum GameServer {
99
China = 'China',
1010
}
1111

12+
export const EquipmentCategories = [
13+
'Hat', 'Gloves', 'Shoes',
14+
'Bag', 'Badge', 'Hairpin',
15+
'Charm', 'Watch', 'Necklace',
16+
] as const;
17+
export type EquipmentCategory = typeof EquipmentCategories[number];
18+
1219
export interface Equipment {
1320
id: string
14-
category: string
21+
category: EquipmentCategory
1522
tier: number
1623
icon: string
1724
jpName: string

0 commit comments

Comments
 (0)