Skip to content

Commit

Permalink
Merge pull request #10499 from DestinyItemManager/artifice-exotic-sup…
Browse files Browse the repository at this point in the history
…port

Artifice exotic support
  • Loading branch information
nev-r authored Jun 6, 2024
2 parents a0b70f3 + e7be751 commit 3642180
Show file tree
Hide file tree
Showing 11 changed files with 59 additions and 14 deletions.
4 changes: 4 additions & 0 deletions config/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -596,9 +596,12 @@
"All": "All",
"AnyExotic": "Any Exotic",
"AnyExoticDescription": "Sets must contain an exotic, but any exotic will do.",
"Artifice": "Artifice",
"AssumeMasterwork": "Assume Masterwork",
"AssumeMasterworkOptions": {
"All": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)",
"AllWithArtificeExotic": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nExotic: $t(LoadoutBuilder.AssumeMasterworkOptions.ArtificeExotic)",
"ArtificeExotic": "Enhanced to accept Artifice stat mods.",
"Legendary": "Legendary: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nExotic: $t(LoadoutBuilder.AssumeMasterworkOptions.Current)",
"None": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Current)",
"Current": "Current stats, assumed energy level at least {{minLoItemEnergy}}.",
Expand All @@ -612,6 +615,7 @@
"ExcludeItem": "Exclude Item",
"ExcludedItems": "Excluded Items",
"Exotic": "Exotic Armor",
"MwExotic": "Exotic",
"ExistingLoadout": "Existing Loadout",
"ExoticSpecialCategory": "Special",
"Filter": "Settings",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@
},
"dependencies": {
"@babel/runtime": "^7.24.5",
"@destinyitemmanager/dim-api-types": "^1.31.0",
"@destinyitemmanager/dim-api-types": "^1.32.0",
"@fortawesome/fontawesome-free": "^5.15.4",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/react-fontawesome": "^0.2.1",
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 6 additions & 1 deletion src/app/loadout-builder/filter/EnergyOptions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,15 @@ export default function EnergyOptions({
value: AssumeArmorMasterwork.Legendary,
},
{
label: t('LoadoutBuilder.All'),
label: `+ ${t('LoadoutBuilder.MwExotic')}`, // used to be t('LoadoutBuilder.All')
tooltip: t('LoadoutBuilder.AssumeMasterworkOptions.All'),
value: AssumeArmorMasterwork.All,
},
{
label: `+ ${t('LoadoutBuilder.Artifice')}`,
tooltip: t('LoadoutBuilder.AssumeMasterworkOptions.AllWithArtificeExotic'), // includes t('LoadoutBuilder.AssumeMasterworkOptions.ArtificeExotic')
value: AssumeArmorMasterwork.ArtificeExotic,
},
],
[],
);
Expand Down
10 changes: 9 additions & 1 deletion src/app/loadout-builder/process/mappers.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AssumeArmorMasterwork } from '@destinyitemmanager/dim-api-types';
import { D2ManifestDefinitions } from 'app/destiny2/d2-definitions';
import { isPluggableItem } from 'app/inventory/store/sockets';
import { calculateAssumedItemEnergy } from 'app/loadout/armor-upgrade-utils';
Expand Down Expand Up @@ -82,12 +83,19 @@ export function mapDimItemToProcessItem({
? _.sumBy(modsForSlot, (mod) => mod.plug.energyCost?.energyCost || 0)
: 0;

const thisIsArtifice = isArtifice(dimItem);
// as of TFS, [relevant, modern] exotics can use artifice stat mods, if the user pays to enhance the armor
const spoofArtifice =
!thisIsArtifice &&
dimItem.isExotic &&
armorEnergyRules.assumeArmorMasterwork === AssumeArmorMasterwork.ArtificeExotic;

return {
id,
hash,
name,
isExotic,
isArtifice: isArtifice(dimItem),
isArtifice: thisIsArtifice || spoofArtifice,
power,
stats: statMap,
remainingEnergyCapacity: capacity - modsCost,
Expand Down
10 changes: 9 additions & 1 deletion src/app/loadout/loadout-ui/Sockets.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ const undesirablePlugs = [
PlugCategoryHashes.V460PlugsArmorMasterworksStatResistance2,
PlugCategoryHashes.V460PlugsArmorMasterworksStatResistance3,
PlugCategoryHashes.V460PlugsArmorMasterworksStatResistance4,
PlugCategoryHashes.EnhancementsArtificeExotic, // the cost socket you pay for by"plug"ging it in-game, to do an artifice upgrade
];

/**
Expand Down Expand Up @@ -91,7 +92,14 @@ function Sockets({
// but always include specialty mod slots, Vow mods don't have
// an itemTypeDisplayName https://github.com/Bungie-net/api/issues/1620
(toSave.itemTypeDisplayName ||
modTypeTagByPlugCategoryHash[toSave.plug.plugCategoryHash as PlugCategoryHashes])
modTypeTagByPlugCategoryHash[toSave.plug.plugCategoryHash as PlugCategoryHashes]) &&
// either it's some other kind of mod-slot, give it a pass, or
(socket.plugged?.plugDef.plug.plugCategoryHash !== PlugCategoryHashes.EnhancementsArtifice ||
// if it IS an artifice slot, then we render it
// if it's already paid for (visibleInGame)
socket.visibleInGame ||
// or if LO has placed a mod in it anyway, due to an upgrades assumption
toSave.hash !== socket.emptyPlugItemHash)
) {
modsAndWhitelist.push({
plugDef: toSave,
Expand Down
8 changes: 7 additions & 1 deletion src/app/loadout/mod-assignment-utils.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { AssumeArmorMasterwork } from '@destinyitemmanager/dim-api-types';
import { D2ManifestDefinitions } from 'app/destiny2/d2-definitions';
import { DimItem, DimSockets, PluggableInventoryItemDefinition } from 'app/inventory/item-types';
import { getEnergyUpgradePlugs } from 'app/inventory/store/energy';
Expand Down Expand Up @@ -307,7 +308,12 @@ export function fitMostMods({
}

// Artifice mods are free and thus can be greedily assigned.
const artificeItems = items.filter(isArtifice);
const artificeItems = items.filter(
(i) =>
(i.isExotic &&
armorEnergyRules.assumeArmorMasterwork === AssumeArmorMasterwork.ArtificeExotic) ||
isArtifice(i),
);
for (const artificeMod of artificeMods) {
let targetItemIndex = artificeItems.findIndex((item) =>
item.sockets?.allSockets.some((socket) => socket.plugged?.plugDef.hash === artificeMod.hash),
Expand Down
5 changes: 3 additions & 2 deletions src/app/search/items/search-filters/sockets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
countEnhancedPerks,
getIntrinsicArmorPerkSocket,
getSocketsByCategoryHash,
isSocketEmpty,
matchesCuratedRoll,
} from 'app/utils/socket-utils';
import { StringLookup } from 'app/utils/util-types';
Expand Down Expand Up @@ -332,8 +333,8 @@ const socketFilters: ItemFilterDefinition[] = [
return Boolean(
socket?.plugged &&
// rules out items where enhancing hasn't even started
// if "empty" is plugged, there's a socket offering enhancement to the player
socket.emptyPlugItemHash !== socket.plugged.plugDef.hash &&
// (the "empty" socket is one offering enhancement to the player)
!isSocketEmpty(socket) &&
// rules out half-enhanced items
// the game explicitly warns you that half-enhanced items stop looking masterworked
item.masterwork,
Expand Down
11 changes: 10 additions & 1 deletion src/app/utils/item-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -372,7 +372,16 @@ export function getStatValuesByHash(item: DimItem, byWhichValue: 'base' | 'value
*/
export function isArtifice(item: DimItem) {
return Boolean(
item.sockets?.allSockets.some((socket) => socket.plugged?.plugDef.hash === ARTIFICE_PERK_HASH),
item.sockets?.allSockets.some(
(socket) =>
// exotic armor has the artifice slot all the time, and it's usable when it's reported as visible
socket.visibleInGame &&
socket.plugged &&
// in a better world, you'd only need to check this, because there's a "empty mod slot" item specifically for artifice slots.
(socket.plugged.plugDef.plug.plugCategoryHash === PlugCategoryHashes.EnhancementsArtifice ||
// but some of those have the *generic* "empty mod slot" item plugged in, so we fall back to keeping an eye out for the intrinsic
socket.plugged.plugDef.hash === ARTIFICE_PERK_HASH),
),
);
}

Expand Down
4 changes: 2 additions & 2 deletions src/app/utils/socket-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -277,7 +277,7 @@ function filterSocketCategories(
* This shows empty catalyst sockets when the weapon has a catalyst
* because it is useful info...
*/
function isSocketEmpty(socket: DimSocket) {
export function isSocketEmpty(socket: DimSocket) {
return (
socket.plugged?.plugDef.hash === socket.emptyPlugItemHash &&
socket.plugged?.plugDef.plug.plugCategoryHash !== PlugCategoryHashes.V400EmptyExoticMasterwork
Expand Down Expand Up @@ -346,7 +346,7 @@ export function getWeaponSockets(
// only show memento socket if it isn't empty
(socket.plugged.plugDef.plug.plugCategoryHash !==
PlugCategoryHashes.CraftingRecipesEmptySocket ||
socket.emptyPlugItemHash !== socket.plugged.plugDef.hash),
!isSocketEmpty(socket)),
);

return {
Expand Down
4 changes: 4 additions & 0 deletions src/locale/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -629,9 +629,12 @@
"All": "All",
"AnyExotic": "Any Exotic",
"AnyExoticDescription": "Sets must contain an exotic, but any exotic will do.",
"Artifice": "Artifice",
"AssumeMasterwork": "Assume Masterwork",
"AssumeMasterworkOptions": {
"All": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)",
"AllWithArtificeExotic": "All armor: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nExotic: $t(LoadoutBuilder.AssumeMasterworkOptions.ArtificeExotic)",
"ArtificeExotic": "Enhanced to accept Artifice stat mods.",
"Current": "Current stats, assumed energy level at least {{minLoItemEnergy}}.",
"Legendary": "Legendary: $t(LoadoutBuilder.AssumeMasterworkOptions.Masterworked)\nExotic: $t(LoadoutBuilder.AssumeMasterworkOptions.Current)",
"Masterworked": "+2 in each stat, assumed energy level 10.",
Expand All @@ -658,6 +661,7 @@
"LockItem": "Pin item",
"MissingClass": "Build is for: {{className}}",
"MissingClassDescription": "The build you're trying to view is for a character class you don't have.",
"MwExotic": "Exotic",
"NoBuildsFoundExplainer": {
"ActiveSearchQuery": "An active search query is restricting the items DIM can include in builds",
"AllowAutoStatMods": "Allow DIM to automatically include additional stat mods",
Expand Down

0 comments on commit 3642180

Please sign in to comment.