Skip to content

Commit

Permalink
related items detection
Browse files Browse the repository at this point in the history
  • Loading branch information
giniedp committed Oct 7, 2023
1 parent 1105fd9 commit ff298b1
Show file tree
Hide file tree
Showing 5 changed files with 215 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ <h3 class="bg-base-300 font-bold px-4 py-2">Loot Table</h3>
<div class="pb-4 px-4 flex flex-col gap-2" *ngIf="card.itemSet$ | async; let gearset">
<div *ngIf="gearset.items?.length > 1">
<h3 class="text-center font-bold mb-1">Set Items</h3>
<div class="flex flex-row gap-3 justify-center">
<div class="flex flex-row flex-wrap gap-2 justify-center">
<a
[tooltip]="item.ItemTypeDisplayName | nwText"
[tooltipClass]="'bg-base-200'"
Expand All @@ -73,17 +73,17 @@ <h3 class="text-center font-bold mb-1">Set Items</h3>
</a>
</div>
</div>
<div *ngIf="gearset.otherVersions.length > 1">
<h3 class="text-center font-bold mb-1">Variant Items</h3>
<div class="flex flex-row gap-3 justify-center">
<div *ngIf="gearset.variants?.length > 1">
<h3 class="text-center font-bold mb-1">Variants</h3>
<div class="flex flex-row flex-wrap gap-2 justify-center">
<a
[tooltip]="itemVersion(item)"
[tooltipClass]="'bg-base-200'"
[nwbItemIcon]="item"
[rarity]="itemRarity(item)"
[isNamed]="itemNamed(item)"
[solid]="true"
*ngFor="let item of gearset.otherVersions"
*ngFor="let item of gearset.variants"
[routerLink]="['/items/table', item.ItemID]"
[routerLinkActive]="['outline']"
[queryParamsHandling]="'preserve'"
Expand All @@ -92,17 +92,17 @@ <h3 class="text-center font-bold mb-1">Variant Items</h3>
</a>
</div>
</div>
<div *ngIf="gearset.otherTiers.length > 1">
<h3 class="text-center font-bold mb-1">Tier Items</h3>
<div class="flex flex-row gap-3 justify-center">
<div *ngIf="gearset.tiers?.length > 1">
<h3 class="text-center font-bold mb-1">Tier Variants</h3>
<div class="flex flex-row flex-wrap gap-2 justify-center">
<a
[tooltip]="itemTier(item)"
[tooltipClass]="'bg-base-200'"
[nwbItemIcon]="item"
[rarity]="itemRarity(item)"
[isNamed]="itemNamed(item)"
[solid]="true"
*ngFor="let item of gearset.otherTiers"
*ngFor="let item of gearset.tiers"
[routerLink]="['/items/table', item.ItemID]"
[routerLinkActive]="['outline']"
[queryParamsHandling]="'preserve'"
Expand Down
12 changes: 11 additions & 1 deletion apps/web/app/pages/database/items/item-detail-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,14 @@ import { Dialog } from '@angular/cdk/dialog'
import { CommonModule } from '@angular/common'
import { ChangeDetectionStrategy, Component, TemplateRef } from '@angular/core'
import { ActivatedRoute, RouterModule } from '@angular/router'
import { getItemIconPath, getItemRarity, getItemTierAsRoman, getItemVersionString, isItemNamed } from '@nw-data/common'
import {
getItemIconPath,
getItemRarity,
getItemRarityLabel,
getItemTierAsRoman,
getItemVersionString,
isItemNamed,
} from '@nw-data/common'
import { ItemDefinitionMaster } from '@nw-data/generated'
import { TranslateService } from '~/i18n'
import { NwModule } from '~/nw'
Expand Down Expand Up @@ -93,6 +100,9 @@ export class ItemDetailPageComponent {
protected itemRarity(item: ItemDefinitionMaster) {
return getItemRarity(item)
}
protected itemRarityLabel(item: ItemDefinitionMaster) {
return getItemRarityLabel(getItemRarity(item))
}
protected itemNamed(item: ItemDefinitionMaster) {
return isItemNamed(item)
}
Expand Down
148 changes: 119 additions & 29 deletions apps/web/app/widgets/data/item-detail/item-detail.store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ import {
selectSalvageInfo,
selectStatusEffectIds,
} from './selectors'
import { ItemDefinitionMaster } from '@nw-data/generated'
import { ItemClass, ItemDefinitionMaster } from '@nw-data/generated'

export interface ItemDetailState {
entityId?: string
Expand Down Expand Up @@ -291,49 +291,139 @@ function collectArtifactTasks(item: ItemDefinitionMaster, db: NwDbService) {
})
)
}
export interface ItemCollections {
items?: ItemDefinitionMaster[]
tiers?: ItemDefinitionMaster[]
variants?: ItemDefinitionMaster[]
}

function selectItemSet(item: ItemDefinitionMaster, itemsSet: Set<ItemDefinitionMaster>) {
function selectItemSet(item: ItemDefinitionMaster, itemsSet: Set<ItemDefinitionMaster>): ItemCollections {
if (!item || !itemsSet) {
return null
}

// console.log({
// item,
// itemsSet: Array.from(itemsSet?.values()),
// })

const meta = getItemMeta(item)
const items = Array.from(itemsSet.values()).map(getItemMeta)
if (!meta.mainCategory) {
const items = Array.from(itemsSet.values())
.map(getItemMeta)
.filter((it) => !!it)

// console.log({ items })
if (!meta?.mainCategory) {
return null
}
const tierItems = items.filter(
(it) => it.mainCategory === meta.mainCategory && it.subCategory === meta.subCategory && it.version === meta.version
)
const variantItems = items.filter(
(it) => it.mainCategory === meta.mainCategory && it.subCategory === meta.subCategory && it.tier === meta.tier
)
const gearset = items.filter(
(it) => it.subCategory === meta.subCategory && it.version === meta.version && it.tier === meta.tier
)

if (gearset.length === 1 && tierItems.length === 1 && variantItems.length === 1) {
if (meta.mainCategory === 'Resource') {
return {
tiers: items.filter((it) => it.mainCategory === meta.mainCategory).map((it) => it.item),
}
}

const itemSet = items.filter((it) => {
return (
it.subCategory === meta.subCategory &&
it.version === meta.version &&
it.tier === meta.tier &&
it.rarity === meta.rarity
)
})
const tierVariants = items.filter((it) => {
return (
it.mainCategory === meta.mainCategory &&
it.subCategory === meta.subCategory &&
it.version === meta.version &&
it.rarity === meta.rarity
)
})
const variants = items.filter((it) => {
return it.mainCategory === meta.mainCategory && it.subCategory === meta.subCategory && it.tier === meta.tier
})

// console.log({ gearset, tierVariants, variants })
if (itemSet.length === 1 && tierVariants.length === 1 && variants.length === 1) {
return null
}
return {
items: gearset.map((it) => it.item),
otherTiers: tierItems.map((it) => it.item),
otherVersions: variantItems.map((it) => it.item),
items: itemSet.map((it) => it.item),
tiers: tierVariants.map((it) => it.item),
variants: variants.map((it) => it.item),
}
}

function getItemMeta(item: ItemDefinitionMaster) {
return {
item: item,
version: getItemVersionString(item),
tier: item.Tier,
subCategory: getFirstItemClassOf(item, ['Light', 'Medium', 'Heavy']),
mainCategory: getFirstItemClassOf(item, [
'EquippableChest',
'EquippableFeet',
'EquippableHands',
'EquippableHead',
'EquippableLegs',
]),
const armorClass = getFirstItemClassOf(item, [
'EquippableChest',
'EquippableFeet',
'EquippableHands',
'EquippableHead',
'EquippableLegs',
])
if (armorClass) {
return {
item: item,
version: getItemVersionString(item),
tier: item.Tier,
rarity: getItemRarity(item),
subCategory: getFirstItemClassOf(item, ['Light', 'Medium', 'Heavy']),
mainCategory: armorClass,
}
}
const weaponClass = getFirstItemClassOf(item, ['EquippableMainHand', 'EquippableTwoHand', 'EquippableOffHand'])
if (weaponClass) {
return {
item: item,
version: getItemVersionString(item),
tier: item.Tier,
rarity: getItemRarity(item),
subCategory: 'weapon',
mainCategory: getFirstItemClassOf(item, [
'2HAxe',
'2HHammer',
'Axe',
'Blunderbuss',
'Bow',
'FireStaff',
'Flail',
'GreatSword',
'Hatchet',
'IceMagic',
'KiteShield',
'LifeStaff',
'Musket',
'Rapier',
'RoundShield',
'Spear',
'Sword',
'TowerShield',
'VoidGauntlet',
]),
}
}
const jevleryClass = getFirstItemClassOf(item, ['EquippableAmulet', 'EquippableRing', 'EquippableToken'])
if (jevleryClass) {
return {
item: item,
version: getItemVersionString(item),
tier: item.Tier,
rarity: getItemRarity(item),
subCategory: 'jevlery',
mainCategory: jevleryClass,
}
}
const resourceClass = getFirstItemClassOf(item, ['Resource'])
if (resourceClass) {
return {
item: item,
version: getItemVersionString(item),
tier: item.Tier,
rarity: getItemRarity(item),
subCategory: resourceClass,
mainCategory: resourceClass,
}
}
return null
}
85 changes: 75 additions & 10 deletions libs/nw-data/common/item.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
import { damageForTooltip } from './damage'
import { CaseInsensitiveMap } from './utils/caseinsensitive-map'
import { eqCaseInsensitive } from './utils/caseinsensitive-compare'
import { flatten, groupBy } from 'lodash'

export function isMasterItem(item: unknown): item is ItemDefinitionMaster {
return item != null && typeof item === 'object' && 'ItemID' in item
Expand Down Expand Up @@ -664,13 +665,46 @@ export function getItemCostumeId(item: ItemDefinitionMaster) {
}

const ITEM_ID_TOKEN_LOAD = ['heavy', 'light', 'medium']
const ITEM_ID_TOKEN_TIER = ['t1', 't2', 't3', 't4', 't5']
const ITEM_ID_TOKEN_TIER = ['t1', 't2', 't3', 't4', 't5', 't51', 't52', 't53', 't54']
const ITEM_ID_TOKEN_VERSION = ['v1', 'v2', 'v3', 'v4', 'v5', 'new', 'xpac']
const ITEM_ID_TOKEN_TRASH = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h']
const ITEM_ID_TOKEN_HEAD = ['cowl', 'hat', 'head', 'helm', 'masque', 'mask', 'crown', 'tiara']
const ITEM_ID_TOKEN_CHEST = ['breastplate', 'chestguard', 'chest', 'coat', 'shirt', 'robe']
const ITEM_ID_TOKEN_HANDS = ['gauntlets', 'gloves', 'handcovers', 'hands']
const ITEM_ID_TOKEN_LEGS = ['greaves', 'legguards', 'pants', 'thighguards', 'leggings']
const ITEM_ID_TOKEN_FEET = ['boots', 'feets', 'feet', 'gloves', 'legs', 'sabatons', 'shoes']
const ITEM_ID_TOKEN_JEWLERY = ['amulet', 'earring', 'ring']
const ITEM_ID_TOKEN_ATTR = ['con', 'dex', 'str', 'foc', 'int']
const ITEM_ID_TOKEN_WEAPON = [
'1h',
'2h',
'blunderbuss',
'bow',
'elementalgauntletice',
'elementalstafffire',
'firestaff',
'flail',
'gauntletice',
'gauntletvoid',
'greataxe',
'greatsword',
'hatchet',
'icegauntlet',
'kite',
'lifestaff',
'longsword',
'musket',
'rapier',
'round',
'shield',
'spear',
'stafffire',
'stafflife',
'sword',
'tower',
'voidgauntlet',
'warhammer',
]
const ITEM_ID_TOKEN_TOKENS = [
...ITEM_ID_TOKEN_LOAD,
...ITEM_ID_TOKEN_TIER,
Expand All @@ -680,29 +714,60 @@ const ITEM_ID_TOKEN_TOKENS = [
...ITEM_ID_TOKEN_LEGS,
...ITEM_ID_TOKEN_FEET,
...ITEM_ID_TOKEN_VERSION,
...ITEM_ID_TOKEN_JEWLERY,
...ITEM_ID_TOKEN_WEAPON,
...ITEM_ID_TOKEN_TRASH,
//...ITEM_ID_TOKEN_ATTR,
]

export function tokenizeItemID(itemID: string) {
export function tokenizeItemID(itemID: string): string[] {
if (!itemID) {
return null
}
return itemID
.replace(/([^A-Z])([A-Z])/g, '$1 $2')
.replace(/(\d\d\d)/g, ' $1 ') // gear score
.toLowerCase()
.split(/[\s_]/)
.filter((it) => !!it)
return (
itemID
.replace(/^1H/, '1h ')
.replace(/^2H/, '2h ')
.replace(/([^A-Z])([A-Z])/g, '$1 $2')
// separate gear score values
.replace(/(\d\d\d)/g, ' $1 ')
// separate trailing numbers (except tier and version)
.replace(/([^VT\d])(\d)/g, '$1 $2')
// collapse whitespaces
.replace(/_/g, ' ')
.replace(/\s+/g, ' ')
// join tokens that belong together
.replace(/(Elemental) (Gauntlet) (Ice)/g, '$1$2$3')
.replace(/(Elemental) (Staff) (Fire)/g, '$1$2$3')
.replace(/(Void|Ice|Gauntlet) (Gauntlet|Void|Ice)/g, '$1$2')
.replace(/(Fire|Life|Staff) (Fire|Life|Staff)/g, '$1$2')
.replace(/(Great) (Axe|Sword)/g, '$1$2')
.toLowerCase()
.split(/\s/)
.filter((it) => !!it)
)
}

export function checkItemSet(items: ItemDefinitionMaster[]) {
items = items.filter((it) => it.ItemType === 'Weapon')
const tokens = flatten(items.map((it) => tokenizeItemID(it.ItemID)))
const data = Array.from(Object.entries(groupBy(tokens, (it) => it)))
.map(([key, value]) => [key, value.length] as const)
.sort((a, b) => b[1] - a[1])
console.log(data)
}
export function getItemSetFamilyName(item: Pick<ItemDefinitionMaster, 'ItemID'>) {
const tokens = tokenizeItemID(item?.ItemID) || []
const familyTokens = tokens.filter((token) => !ITEM_ID_TOKEN_TOKENS.includes(token) && !token.match(/^\d\d\d$/))
const familyTokens = tokens.filter(
(token) => !ITEM_ID_TOKEN_TOKENS.includes(token) && !token.match(/^\d\d\d$/) && !token.match(/^t\d+$/)
)
return familyTokens.join(' ')
}

export function getItemVersionString(item: Pick<ItemDefinitionMaster, 'ItemID'>) {
const tokens = tokenizeItemID(item?.ItemID) || []
const version = tokens.filter((token) => ITEM_ID_TOKEN_VERSION.includes(token)).join(' ')
const tierVersion = tokens.filter((token) => ITEM_ID_TOKEN_TIER.includes(token)).find((it) => it.match(/^t\d\d+$/))
const gs = tokens.find((token) => token.match(/^\d\d\d$/))
return [version || '', gs ? `gs${gs}` : ''].filter((it) => !!it).join(' ')
return [version || '', gs ? `gs${gs}` : '', tierVersion || ''].filter((it) => !!it).join(' ')
}
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "nw-buddy",
"version": "3.0.0",
"version": "3.0.0-1",
"description": "New World Buddy",
"keywords": [],
"main": "dist/electron/main.js",
Expand Down

0 comments on commit ff298b1

Please sign in to comment.