Skip to content

Commit

Permalink
Merge pull request #10537 from DestinyItemManager/global-power-level
Browse files Browse the repository at this point in the history
account-wide power level calc
  • Loading branch information
nev-r authored Jun 13, 2024
2 parents f3375f3 + 1c81e96 commit 7964bcc
Show file tree
Hide file tree
Showing 13 changed files with 215 additions and 98 deletions.
5 changes: 5 additions & 0 deletions config/i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1233,6 +1233,11 @@
"Discipline": "Discipline",
"Intellect": "Intellect",
"MaxGearPower": "Maximum Power of equippable gear",
"DropLevel": "Account Power",
"DropLevelExplanation1": "Account Power is the base current level when calculating the increased level of Powerful and Pinnacle rewards.",
"DropLevelExplanation2": "Account Power uses the highest level item in each slot, regardless of required Class or the \"One Exotic\" rule.",
"EquippableGear": "Equippable Gear",
"MaxGearPowerOneExoticRule": "Maximum Power of equippable gear\n(only one Exotic armor piece equipped)",
"MaxGearPowerAll": "Maximum Power of all gear",
"PowerModifier": "Power granted by seasonal experience progression",
"MaxTotalPower": "Maximum total Power",
Expand Down
20 changes: 17 additions & 3 deletions src/app/character-tile/CharacterTile.m.scss
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,17 @@
.vaultTile {
composes: tileCommon;
display: grid;
grid-template-areas: 'emblem class vaultCapacity' !important;
grid-template-areas: 'emblem class power' !important;
grid-template-columns: 46px 1fr min-content;
grid-template-rows: 1fr;
align-items: center;
box-sizing: border-box;
gap: 0 6px;
padding: 0 6px;

@include phone-portrait {
grid-template-areas: 'emblem class vaultCapacity' !important;
}
// The vault needs a little border to stand out against some backgrounds
border: 1px solid rgba(0, 0, 0, 0.3);
border-right: none;
Expand Down Expand Up @@ -131,8 +134,6 @@

// Current power level
.powerLevel {
composes: bigText;
grid-area: power;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif, 'Destiny Symbols';
font-weight: 500;
color: $power;
Expand All @@ -145,6 +146,19 @@
}
}

.bigPowerLevel {
composes: bigText;
grid-area: power;
}

.smallPowerLevel {
text-align: right;

:global(.app-icon) {
font-size: 80%;
}
}

// The max power shown on mobile under the current power
.maxTotalPower {
composes: smallText;
Expand Down
2 changes: 2 additions & 0 deletions src/app/character-tile/CharacterTile.m.scss.d.ts

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

18 changes: 16 additions & 2 deletions src/app/character-tile/CharacterTile.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import FractionalPowerLevel from 'app/dim-ui/FractionalPowerLevel';
import type { DimStore, DimTitle } from 'app/inventory/store-types';
import { powerLevelSelector } from 'app/inventory/store/selectors';
import { allPowerLevelsSelector, powerLevelSelector } from 'app/inventory/store/selectors';
import { AppIcon, powerActionIcon } from 'app/shell/icons';
import { useIsPhonePortrait } from 'app/shell/selectors';
import VaultCapacity from 'app/store-stats/VaultCapacity';
Expand Down Expand Up @@ -44,7 +45,7 @@ export default memo(function CharacterTile({ store }: { store: DimStore }) {
<div className={styles.bottom}>
{store.titleInfo ? <Title titleInfo={store.titleInfo} /> : store.race}
</div>
<div className={styles.powerLevel}>
<div className={clsx(styles.powerLevel, styles.bigPowerLevel)}>
<AppIcon icon={powerActionIcon} />
{store.powerLevel}
</div>
Expand All @@ -55,14 +56,27 @@ export default memo(function CharacterTile({ store }: { store: DimStore }) {

function VaultTile({ store }: { store: DimStore }) {
const isPhonePortrait = useIsPhonePortrait();
const powerLevel = Object.values(useSelector(allPowerLevelsSelector))[0];

return (
<div className={styles.vaultTile}>
<img className={styles.vaultEmblem} src={store.icon} height={40} width={40} />
<div className={styles.vaultName}>{store.className}</div>
{!isPhonePortrait && (
<div className={clsx(styles.powerLevel, styles.bigPowerLevel)}>
<AppIcon icon={powerActionIcon} />
<FractionalPowerLevel power={powerLevel.dropPower} />
</div>
)}
{isPhonePortrait && (
<div className={styles.vaultCapacity}>
<VaultCapacity />
<span className={clsx(styles.powerLevel, styles.smallPowerLevel)}>
<AppIcon icon={powerActionIcon} />
</span>
<span className={clsx(styles.powerLevel, styles.smallPowerLevel)}>
<FractionalPowerLevel power={powerLevel.dropPower} />
</span>
</div>
)}
</div>
Expand Down
32 changes: 27 additions & 5 deletions src/app/gear-power/GearPower.m.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@

.gearPowerSheetContent {
margin: 0 20px 20px;
width: min-content;
white-space: pre-wrap;
}

.gearPowerHeader {
display: flex;
margin-right: 10px;
align-items: center;

img {
> img {
margin-right: 10px;
height: 48px;
width: 48px;
Expand All @@ -32,12 +35,34 @@

.powerLevel {
color: $power;

font-size: 1.4em;
:global(.app-icon) {
font-size: 60%;
vertical-align: 45%;
margin-right: 2px;
}
img {
height: 1.2em;
width: auto;
margin: 0;
vertical-align: text-bottom;
filter: none !important;
}
}
:global(.selected) {
.powerLevel {
color: black;
}
}

.toggle {
margin: 10px 10px 15px;
}

.powerToggleButton {
display: flex;
flex-direction: column;
align-items: center;
}

.gearGrid {
Expand Down Expand Up @@ -145,9 +170,6 @@
}
}

.notes {
max-width: 400px;
}
.footNote {
margin: 10px auto 0;
color: #999;
Expand Down
3 changes: 2 additions & 1 deletion src/app/gear-power/GearPower.m.scss.d.ts

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

91 changes: 57 additions & 34 deletions src/app/gear-power/GearPower.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { AlertIcon } from 'app/dim-ui/AlertIcon';
import BungieImage from 'app/dim-ui/BungieImage';
import FractionalPowerLevel from 'app/dim-ui/FractionalPowerLevel';
import { SetFilterButton } from 'app/dim-ui/SetFilterButton';
import RadioButtons from 'app/dim-ui/RadioButtons';
import BucketIcon from 'app/dim-ui/svgs/BucketIcon';
import { t } from 'app/i18next-t';
import { locateItem } from 'app/inventory/locate-item';
import { powerLevelSelector } from 'app/inventory/store/selectors';
import { classFilter } from 'app/search/items/search-filters/known-values';
import { AppIcon, powerActionIcon } from 'app/shell/icons';
import { RootState } from 'app/store/types';
import { LookupTable } from 'app/utils/util-types';
import clsx from 'clsx';
import rarityIcons from 'data/d2/engram-rarity-icons.json';
import { BucketHashes } from 'data/d2/generated-enums';
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { useSubscription } from 'use-subscription';
import Sheet from '../dim-ui/Sheet';
Expand Down Expand Up @@ -41,35 +41,62 @@ export default function GearPower() {

const powerLevel = useSelector((state: RootState) => powerLevelSelector(state, selectedStoreId));

const [whichGear, setWhichGear] = useState<'drop' | 'equip'>('drop');

if (!selectedStore || !powerLevel) {
return null;
}

const header = (
<div className={styles.gearPowerHeader}>
<img src={selectedStore.icon} />
<div>
<h1>{selectedStore.name}</h1>
<h1 className={styles.powerLevel}>
<AppIcon icon={powerActionIcon} />
<FractionalPowerLevel power={powerLevel.maxGearPower} />
</h1>
</div>
<h1>{selectedStore.name}</h1>
</div>
);

const exampleItem = powerLevel.highestPowerItems.find(
(i) => i.classType === selectedStore.classType,
const powerFloor = Math.floor(
whichGear === 'drop' ? powerLevel.dropPower : powerLevel.maxEquippableGearPower,
);
const powerFloor = Math.floor(powerLevel.maxGearPower);
const classFilterString = exampleItem && classFilter.fromItem(exampleItem);
const maxItemsSearchString = classFilterString && `${classFilterString} is:maxpower`;

const items =
whichGear === 'drop' ? powerLevel.dropCalcItems : powerLevel.maxEquippablePowerItems;
return (
<Sheet onClose={reset} header={header} sheetClassName={styles.gearPowerSheet}>
<RadioButtons
className={styles.toggle}
value={whichGear}
onChange={setWhichGear}
options={[
{
label: (
<div className={styles.powerToggleButton}>
<span>{t('Stats.EquippableGear')}</span>
<span className={styles.powerLevel}>
<AppIcon icon={powerActionIcon} />
<FractionalPowerLevel power={powerLevel.maxEquippableGearPower} />
</span>
</div>
),
tooltip: t('Stats.MaxGearPowerOneExoticRule'),
value: 'equip',
},
{
label: (
<div className={styles.powerToggleButton}>
<span>{t('Stats.DropLevel')}</span>
<span className={styles.powerLevel}>
<BungieImage src={rarityIcons.Legendary} />
<FractionalPowerLevel power={powerLevel.dropPower} />
</span>
</div>
),
tooltip: t('Stats.DropLevelExplanation1'),
value: 'drop',
},
]}
/>
<div className={styles.gearPowerSheetContent}>
<div className={styles.gearGrid}>
{powerLevel.highestPowerItems.map((i) => {
{items.map((i) => {
const powerDiff = (powerFloor - i.power) * -1;
const diffSymbol = powerDiff >= 0 ? '+' : '';
const diffClass =
Expand All @@ -96,23 +123,16 @@ export default function GearPower() {
);
})}
</div>
{powerLevel.problems.notOnStore && (
<div className={styles.notes}>
<AlertIcon /> {t('Loadouts.OnWrongCharacterWarning')}
{maxItemsSearchString && (
<p>
<SetFilterButton filter={maxItemsSearchString} />{' '}
{t('Loadouts.OnWrongCharacterAdvice')}
</p>
)}
</div>
)}
{powerLevel.problems.notEquippable && (
<>
<div className={styles.footNote}>* {t('Loadouts.EquippableDifferent1')}</div>
<div className={styles.footNote}>{t('Loadouts.EquippableDifferent2')}</div>
</>
)}
<div className={styles.footNote}>
{whichGear === 'equip' ? (
t('Stats.MaxGearPowerOneExoticRule')
) : (
<>
<p>{t('Stats.DropLevelExplanation1')}</p>
<p>{t('Stats.DropLevelExplanation2')}</p>
</>
)}
</div>
</div>
</Sheet>
);
Expand All @@ -128,3 +148,6 @@ export default function GearPower() {
// </span>
// )}
// </ItemPopupTrigger>

// t('Loadouts.OnWrongCharacterWarning') and t('Loadouts.OnWrongCharacterAdvice') and t('Loadouts.EquippableDifferent1') and t('Loadouts.EquippableDifferent2')
// used to live in this file
Loading

0 comments on commit 7964bcc

Please sign in to comment.