Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions src/lib/characterPreview/ShowcaseRelicsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.Head)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
<RelicPreview
setEditModalOpen={setEditModalOpen}
Expand All @@ -50,6 +51,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.Body)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
<RelicPreview
setEditModalOpen={setEditModalOpen}
Expand All @@ -60,6 +62,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.PlanarSphere)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
</Flex>

Expand All @@ -73,6 +76,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.Hands)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
<RelicPreview
setEditModalOpen={setEditModalOpen}
Expand All @@ -83,6 +87,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.Feet)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
<RelicPreview
setEditModalOpen={setEditModalOpen}
Expand All @@ -93,6 +98,7 @@ export function ShowcaseRelicsPanel(props: {
characterId={characterId}
score={scoredRelics.find((x) => x.part == Constants.Parts.LinkRope)}
showcaseTheme={showcaseColors}
withHoverButtons={source == ShowcaseSource.CHARACTER_TAB}
/>
</Flex>
</Flex>
Expand Down
20 changes: 12 additions & 8 deletions src/lib/optimization/optimizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,33 @@ import { COMPUTE_ENGINE_CPU, Constants, ElementToDamage, Stats } from 'lib/const
import { SavedSessionKeys } from 'lib/constants/constantsSession'
import { getWebgpuDevice } from 'lib/gpu/webgpuDevice'
import { gpuOptimize } from 'lib/gpu/webgpuOptimizer'
import { RelicsByPart } from 'lib/gpu/webgpuTypes'
import { Message } from 'lib/interactions/message'
import { BufferPacker, OptimizerDisplayData } from 'lib/optimization/bufferPacker'
import { calculateBuild } from 'lib/optimization/calculateBuild'
import { ComputedStatsArray } from 'lib/optimization/computedStatsArray'
import { generateContext } from 'lib/optimization/context/calculateContext'
import { FixedSizePriorityQueue } from 'lib/optimization/fixedSizePriorityQueue'
import { generateOrnamentSetSolutions, generateRelicSetSolutions } from 'lib/optimization/relicSetSolver'
import { SortOption } from 'lib/optimization/sortOptions'
import { SortOption, SortOptionProperties } from 'lib/optimization/sortOptions'
import { RelicFilters } from 'lib/relics/relicFilters'
import DB from 'lib/state/db'
import { setSortColumn } from 'lib/tabs/tabOptimizer/optimizerForm/components/RecommendedPresetsButton'
import { activateZeroPermutationsSuggestionsModal, activateZeroResultSuggestionsModal } from 'lib/tabs/tabOptimizer/OptimizerSuggestionsModal'
import { OptimizerTabController } from 'lib/tabs/tabOptimizer/optimizerTabController'
import { TsUtils } from 'lib/utils/TsUtils'
import { Utils } from 'lib/utils/utils'
import { WorkerPool } from 'lib/worker/workerPool'
import { Form } from 'types/form'
import { Relic } from 'types/relic'

// FIXME HIGH

let CANCEL = false
const isFirefox = typeof navigator !== 'undefined' && navigator.userAgent.toLowerCase().indexOf('firefox') > -1

export function calculateCurrentlyEquippedRow(request) {
let relics = Utils.clone(DB.getRelics())
export function calculateCurrentlyEquippedRow(request: Form) {
let relics: Relic[] | RelicsByPart = TsUtils.clone(DB.getRelics())
RelicFilters.calculateWeightScore(request, relics)
relics = relics.filter((x) => x.equippedBy == request.characterId)
relics = RelicFilters.applyMainStatsFilter(request, relics)
Expand All @@ -40,15 +43,16 @@ export function calculateCurrentlyEquippedRow(request) {
}

export const Optimizer = {
cancel: (id) => {
cancel: (id: string) => {
CANCEL = true
WorkerPool.cancel(id)
},

getFilteredRelics: (request: Form) => {
let relics = Utils.clone(DB.getRelics())
let relics = TsUtils.clone(DB.getRelics())
RelicFilters.calculateWeightScore(request, relics)

relics = RelicFilters.applyRelicExcludeFilter(request, relics)
relics = RelicFilters.applyEquippedFilter(request, relics) // will reduce iterations if "off" is selected
relics = RelicFilters.applyEnhanceFilter(request, relics)
relics = RelicFilters.applyGradeFilter(request, relics)
Expand All @@ -71,7 +75,7 @@ export const Optimizer = {
return [relicsByPart, preFilteredRelicsByPart]
},

optimize: async function (request) {
optimize: async function (request: Form) {
CANCEL = false

const teammates = [
Expand Down Expand Up @@ -121,7 +125,7 @@ export const Optimizer = {

OptimizerTabController.scrollToGrid()

window.optimizerGrid.current.api.setGridOption('loading', true)
window.optimizerGrid.current!.api.setGridOption('loading', true)

const context = generateContext(request)

Expand All @@ -131,7 +135,7 @@ export const Optimizer = {
let searched = 0
let resultsShown = false
let results = []
const sortOption = SortOption[request.resultSort]
const sortOption = SortOption[request.resultSort] as SortOptionProperties
const gridSortColumn = request.statDisplay == 'combat' ? sortOption.combatGridColumn : sortOption.basicGridColumn
const resultsLimit = request.resultsLimit || 1024
const queueResults = new FixedSizePriorityQueue(resultsLimit, (a, b) => a[gridSortColumn] - b[gridSortColumn])
Expand Down
2 changes: 1 addition & 1 deletion src/lib/optimization/sortOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,4 +306,4 @@ export const SortOption: {
optimizerKey: Key.SHIELD_VALUE,
isComputedRating: true,
},
}
} as const
119 changes: 100 additions & 19 deletions src/lib/overlays/modals/RelicModal.tsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { CaretRightOutlined } from '@ant-design/icons'
import { Button, Flex, Form, Image, Input, InputNumber, Modal, Radio, Select, theme } from 'antd'
import { Button, Divider, Flex, Form, Image, Input, InputNumber, Modal, Radio, Select, theme } from 'antd'
import { FormInstance } from 'antd/es/form/hooks/useForm'
import i18next from 'i18next'
import { Constants, setToId, Stats, UnreleasedSets } from 'lib/constants/constants'
import { Message } from 'lib/interactions/message'
import { calculateUpgradeValues, RelicForm, RelicUpgradeValues, validateRelic } from 'lib/overlays/modals/relicModalController'
import { Assets } from 'lib/rendering/assets'
import { generateCharacterList } from 'lib/rendering/displayUtils'
import DB from 'lib/state/db'
import CharacterSelect, {
CharacterSelectValueOut,
} from 'lib/tabs/tabOptimizer/optimizerForm/components/CharacterSelect'
import { HeaderText } from 'lib/ui/HeaderText'
import { TsUtils } from 'lib/utils/TsUtils'
import { Utils } from 'lib/utils/utils'
import PropTypes from 'prop-types'
import React, { ReactElement, useEffect, useMemo, useRef, useState } from 'react'
import { useTranslation } from 'react-i18next'
import styled from 'styled-components'
import { Character } from 'types/character'
import { Character, CharacterId } from 'types/character'
import { Relic, Stat } from 'types/relic'

// FIXME MED

const { useToken } = theme

function RadioIcon(props) {
function RadioIcon(props: { value: string; src: string }) {
return (
<Radio.Button value={props.value} style={{ height: 35, width: 50, paddingLeft: 10 }}>
<Image
Expand All @@ -33,15 +35,6 @@ function RadioIcon(props) {
)
}

RadioIcon.propTypes = {
value: PropTypes.string,
src: PropTypes.string,
}

const InputNumberStyled = styled(InputNumber)`
width: 90px
`

function renderMainStat(relic: Relic): Stat {
const mainStat: string = relic.main?.stat
const mainValue: number = relic.main?.value
Expand All @@ -61,7 +54,7 @@ function renderSubstat(relic: Relic, index: number): Stat {
return renderStat(stat, value, relic)
}

function renderStat(stat: string, value: number, relic?: Relic): Stat {
function renderStat<T>(stat: T, value: number, relic?: Relic): { stat: T; value: string | number } {
if (stat == Stats.SPD) {
if (relic?.verified) {
return {
Expand Down Expand Up @@ -129,13 +122,13 @@ export default function RelicModal(props: {
const [upgradeValues, setUpgradeValues] = useState<RelicUpgradeValues[]>([])

useEffect(() => {
let defaultValues = {
let defaultValues: RelicForm = {
grade: 5,
enhance: 15,
part: Constants.Parts.Head,
mainStatType: Constants.Stats.HP,
mainStatValue: Math.floor(Constants.MainStatsValues[Constants.Stats.HP][5].base + Constants.MainStatsValues[Constants.Stats.HP][5].increment * 15),
}
} as RelicForm

const relic = props.selectedRelic
if (!relic || props.type != 'edit') {
Expand All @@ -157,6 +150,8 @@ export default function RelicModal(props: {
substatValue2: renderSubstat(relic, 2).value,
substatType3: renderSubstat(relic, 3).stat,
substatValue3: renderSubstat(relic, 3).value,
excluded: relic.excluded,
excludedCount: relic.excludedCount,
}
}
onValuesChange(defaultValues)
Expand Down Expand Up @@ -458,6 +453,8 @@ export default function RelicModal(props: {
/>
</Flex>
</Flex>
<Divider style={{ margin: 8 }}/>
<RelicRestriction form={relicForm} relic={props.selectedRelic}/>
</Flex>
</Modal>
</Form>
Expand All @@ -483,7 +480,7 @@ function SubstatInput(props: {
}
}

function upgradeClicked(quality: string) {
function upgradeClicked(quality: 'low' | 'mid' | 'high') {
console.log(props, quality)

props.relicForm.setFieldValue(statValueField, props.upgrades[props.index][quality])
Expand Down Expand Up @@ -513,7 +510,7 @@ function SubstatInput(props: {
}, [i18next.resolvedLanguage])

function UpgradeButton(subProps: {
quality: string
quality: 'low' | 'mid' | 'high'
}) {
const value = props.upgrades?.[props.index]?.[subProps.quality]

Expand Down Expand Up @@ -575,6 +572,90 @@ function SubstatInput(props: {
)
}

function RelicRestriction(props: { form: FormInstance; relic?: Relic }) {
const { t } = useTranslation('gameData', { keyPrefix: 'Characters' })
const [singleSelectOpen, setSingleSelectOpen] = useState(false)
const [multiSelectOpen, setMultiSelectOpen] = useState(false)
const [state, setState] = useState(false)
function openReserve() {
setSingleSelectOpen(true)
}
function openExclude() {
setMultiSelectOpen(true)
}
function updateState() {
setState(!state)
}
function handleChange(x: CharacterSelectValueOut<'any'>) {
if (typeof x === 'string') {
// reserve clicked
const excludedIds = Object.values(DB.getMetadata().characters)
.map((character) => character.id)
.filter((id) => id !== x)
props.form.setFieldValue('excluded', excludedIds)
} else {
// exclude clicked
const excludedIds = (
Array.from(x || new Map<CharacterId, boolean>())
.filter((entry) => entry[1])
.map((entry) => entry[0])
)
props.form.setFieldValue('excluded', excludedIds)
}
}
if (!props.relic) return
return (
<Flex>
<div style={{ width: 0, height: 30 }}>
<Form.Item name='excluded'>
<CharacterSelect
selectStyle={{ display: 'none' }}
value={undefined}
externalOpen={multiSelectOpen}
setExternalOpen={setMultiSelectOpen}
onChange={handleChange}
multipleSelect
/>
</Form.Item>
<CharacterSelect
selectStyle={{ display: 'none' }}
value={undefined}
externalOpen={singleSelectOpen}
setExternalOpen={setSingleSelectOpen}
onChange={handleChange}
/>
</div>
<Flex gap={8} style={{ height: 30 }} align='center'>
<Button onClick={openReserve}>
reserve
</Button>
<Button onClick={openExclude}>
exclude
</Button>
<Button onClick={() => {
props.form.setFieldValue('excluded', [])
updateState()
}}
>
clear
</Button>
{
(props.form.getFieldValue('excluded') as CharacterId[]).length === 0
? ''
: (props.form.getFieldValue('excluded') as CharacterId[]).length === Object.keys(DB.getMetadata().characters).length - 1
? `Relic reserved for ${
t(`${
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
Object.keys(DB.getMetadata().characters).filter((x) => !(props.form.getFieldValue('excluded') as CharacterId[]).includes(x))
}.Name` as never) as string
}`
: `Relic excluded for ${(props.form.getFieldValue('excluded') as CharacterId[]).length} characters`
}
</Flex>
</Flex>
)
}

function relicHash(relic: Relic) {
return TsUtils.objectHash({
grade: relic.grade,
Expand Down
Loading
Loading