Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ZO adding basic opt targets to ZO, wrapping up MVPish #2603

Merged
merged 15 commits into from
Jan 24, 2025
29 changes: 27 additions & 2 deletions apps/zzz-frontend/src/app/PageHome.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,29 @@
// TODO: Move this to a lib
import { CardThemed } from '@genshin-optimizer/common/ui'
import { CardContent, Typography } from '@mui/material'

export default function PageHome() {
return <>home page</>
return (
<CardThemed sx={{ my: 1 }}>
<CardContent>
<Typography variant="h5">I know what this looks like...</Typography>
<Typography>
This is an <i>Alpha</i>(desperately unfinished) version of{' '}
<strong>Zenless Optimizer</strong>. You have to understand, this is
the result of asking,
</Typography>
<Typography variant="caption">
"What is the most Optimizer I can, if I was cutting corners like it's
crunch time at a circle factory?" — frzyc, probably
</Typography>
<Typography>
I know a lot of stuff isn't implemented, and the stuff that are, are
super ugly. This is only like 10 hours of coding, cut me some slack.
</Typography>
<Typography sx={{ my: 1 }}>Have an optimal day,</Typography>
<Typography>
<strong>frzyc</strong>
</Typography>
</CardContent>
</CardThemed>
)
}
34 changes: 34 additions & 0 deletions libs/zzz/consts/src/character.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export const allCharacterKeys = [
'Anby',
'Anton',
'AstraYao',
'Ben',
'Billy',
'Burnice',
'Caesar',
'Corin',
'Ellen',
'Evelyn',
'Grace',
'Harumasa',
'Jane',
'Koleda',
'Lighter',
'Lucy',
'Lycaon',
'Miyabi',
'Nekomata',
'Nicole',
'Piper',
'Qingyi',
'Rina',
'Seth',
'Soldier11',
'Soukaku',
'Yanagi',
'ZhuYuan',
] as const
export type CharacterKey = (typeof allCharacterKeys)[number]

export const allLocationKeys = [...allCharacterKeys, ''] as const
export type LocationKey = (typeof allLocationKeys)[number]
90 changes: 89 additions & 1 deletion libs/zzz/consts/src/common.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,110 @@
import { objKeyMap } from '@genshin-optimizer/common/util'
import { allDiscMainStatKeys, allDiscSubStatKeys } from './disc'

export const otherStatKeys = [
// Used by calc, likely will be bundled into pando
'charLvl',
frzyc marked this conversation as resolved.
Show resolved Hide resolved
'enemyDef', // Enemy DEF
'enemyRes_', // Enemy Resistance
'enemyResRed_', // Enemy Resistance Reduction
'enemyResIgn_', // Enemy Resistance Ignore
'dmg_', // Bonus DMG

// Other stats
'impact', // flat impact on character
'anomMas', // flat Anomally Mastery on character
'shield_', // Shield Effect
] as const

export const unCondKeys = [
'uncond_hp',
'uncond_def',
'uncond_atk',
'uncond_hp_',
'uncond_def_',
'uncond_atk_',
] as const

export const allStatKeys = Array.from(
new Set([...allDiscMainStatKeys, ...allDiscSubStatKeys, ...otherStatKeys])
)
export type StatKey = (typeof allStatKeys)[number]

const allElementalKeys = [
'electric',
'fire',
'ice',
'physical',
'ether',
] as const
export type ElementalKey = (typeof allElementalKeys)[number]

export const allAttributeDamageKeys = [
'electric_dmg_',
'fire_dmg_',
'ice_dmg_',
'frost_dmg_',
'physical_dmg_',
'ether_dmg_',
] as const
export type AttributeDamageKey = (typeof allAttributeDamageKeys)[number]

export const allAnomalyDmgKeys = [
'burn',
'shock',
'corruption',
'shatter',
'assault',
] as const
export type AnomalyDamageKey = (typeof allAnomalyDmgKeys)[number]

export const statKeyTextMap: Partial<Record<string, string>> = {
hp_base: 'Base HP',
atk_base: 'Base ATK',
def_base: 'Base DEF',
hp: 'HP',
hp_: 'HP',
atk: 'ATK',
atk_: 'ATK',
def: 'DEF',
def_: 'DEF',
pen: 'PEN',
pen_: 'PEN Ratio',
crit_: 'CRIT Rate',
crit_dmg_: 'CRIT DMG',
enerRegen_: 'Energy Regen',
impact_: 'Impact',
anomMas_: 'Anomaly Mastery',
anomProf: 'Anomaly Proficiency',
...objKeyMap(allAnomalyDmgKeys, (dmg_) => `${dmg_} DMG Bonus`),
dmg_: 'DMG Bonus',
charLvl: 'Character Level',
enemyDef: 'Enemy DEF',
enemyRes_: 'Enemy Resistance',
enemyResRed_: 'Enemy Resistance Reduction',
enemyResIgn_: 'Enemy Resistance Ignore',

initial_hp: 'Initial HP',
initial_def: 'Initial DEF',
initial_atk: 'Initial ATK',
final_hp: 'Final HP',
final_def: 'Final DEF',
final_atk: 'Final ATK',
uncond_hp: 'Unconditional HP',
uncond_def: 'Unconditional DEF',
uncond_atk: 'Unconditional ATK',
uncond_hp_: 'Unconditional HP%',
uncond_def_: 'Unconditional DEF%',
uncond_atk_: 'Unconditional ATK%',
}

const elementalData: Record<ElementalKey, string> = {
electric: 'Electric',
fire: 'Fire',
ice: 'Ice',
physical: 'Physical',
ether: 'Ether',
} as const

Object.entries(elementalData).forEach(([e, name]) => {
statKeyTextMap[`${e}_dmg_`] = `${name} DMG Bonus`
})
2 changes: 0 additions & 2 deletions libs/zzz/consts/src/disc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ export const allElementalDmgMainStatKeys = [
'electric_dmg_',
'fire_dmg_',
'ice_dmg_',
'frost_dmg_',
'physical_dmg_',
'ether_dmg_',
] as const
Expand Down Expand Up @@ -135,7 +134,6 @@ const mainData = {
electric_dmg_: m123,
fire_dmg_: m123,
ice_dmg_: m123,
frost_dmg_: m123,
physical_dmg_: m123,
ether_dmg_: m123,
anomMas_: m123,
Expand Down
1 change: 1 addition & 0 deletions libs/zzz/consts/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
export * from './character'
export * from './common'
export * from './disc'
16 changes: 13 additions & 3 deletions libs/zzz/db/src/Database/DataManagers/DiscDataManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type {
DiscSubStatKey,
} from '@genshin-optimizer/zzz/consts'
import {
allCharacterKeys,
allDiscRarityKeys,
allDiscSetKeys,
allDiscSlotKeys,
Expand Down Expand Up @@ -38,6 +39,17 @@ export class DiscDataManager extends DataManager<
// Generate cache fields
const newDisc = { ...storageObj, id } as ICachedDisc

// rudimentary check for equipment relationship
const oldDisc = super.get(id)
if (newDisc.location && newDisc.location !== oldDisc?.location) {
// remove any other disc from the same character in the same slot
this.values.forEach((d) => {
if (d.location === newDisc.location && d.slotKey === newDisc.slotKey) {
this.set(d.id, { location: '' })
}
})
}

// Check relations and update equipment
/* TODO:
const oldDisc = super.get(id)
Expand Down Expand Up @@ -328,9 +340,7 @@ export function validateDisc(
if (!(plausibleMainStats as DiscMainStatKey[]).includes(mainStatKey))
if (plausibleMainStats.length === 1) mainStatKey = plausibleMainStats[0]
else return undefined // ambiguous mainstat
// TODO:
// if (!location || !allCharacterKeys.includes(location)) location = ''
location = ''
if (location && !allCharacterKeys.includes(location)) location = ''
return {
setKey,
rarity,
Expand Down
3 changes: 2 additions & 1 deletion libs/zzz/db/src/Interfaces/IDisc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import type {
DiscSetKey,
DiscSlotKey,
DiscSubStatKey,
LocationKey,
} from '@genshin-optimizer/zzz/consts'

export interface ISubstat {
Expand All @@ -16,7 +17,7 @@ export interface IDisc {
level: number // 0-15
rarity: DiscRarityKey
mainStatKey: DiscMainStatKey
location: string // TODO: CharacterKey
location: LocationKey
lock: boolean
trash: boolean
substats: ISubstat[]
Expand Down
1 change: 0 additions & 1 deletion libs/zzz/disc-scanner/src/lib/enStringMap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ const elementalData: Record<string, string> = {
electric: 'Electric',
fire: 'Fire',
ice: 'Ice',
frost: 'Frost',
physical: 'Physical',
ether: 'Ether',
} as const
Expand Down
84 changes: 61 additions & 23 deletions libs/zzz/page-optimize/src/BaseStatCard.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import { CardThemed, NumberInputLazy } from '@genshin-optimizer/common/ui'
import { getUnitStr } from '@genshin-optimizer/common/util'
import type { StatKey } from '@genshin-optimizer/zzz/consts'
import { allAttributeDamageKeys } from '@genshin-optimizer/zzz/consts'
import type { LocationKey, StatKey } from '@genshin-optimizer/zzz/consts'
import {
allAttributeDamageKeys,
statKeyTextMap,
unCondKeys,
} from '@genshin-optimizer/zzz/consts'
import type { BaseStats } from '@genshin-optimizer/zzz/solver'
import { CardContent, Stack } from '@mui/material'
const baseKeys = ['hp_base', 'atk_base', 'def_base'] as const
import { LocationAutocomplete } from '@genshin-optimizer/zzz/ui'
import { Box, CardContent, Typography } from '@mui/material'
const baseKeys = ['charLvl', 'hp_base', 'atk_base', 'def_base'] as const
const statKeys: StatKey[] = [
'hp',
'atk',
Expand All @@ -15,36 +20,69 @@ const statKeys: StatKey[] = [
'crit_',
'crit_dmg_',
...allAttributeDamageKeys,
'dmg_',
'impact',
'anomMas',
'anomProf',
'pen_',
'pen',
] as const
const enemyKeys: StatKey[] = [
'enemyDef',
'enemyRes_',
'enemyResRed_',
'enemyResIgn_',
] as const
export default function BaseStatCard({
location,
setLocation,
baseStats,
setBaseStats,
}: {
location: LocationKey
setLocation: (location: LocationKey) => void
baseStats: BaseStats
setBaseStats: (baseStats: BaseStats) => void
}) {
const input = (key: string) => (
<NumberInputLazy
key={key}
sx={{ flexGrow: 1 }}
value={baseStats[key] || 0}
onChange={(v) =>
setBaseStats({
...baseStats,
[key]: v,
})
}
inputProps={{ sx: { textAlign: 'right', minWidth: '5em' } }}
InputProps={{
startAdornment: statKeyTextMap[key] ?? key,
endAdornment: getUnitStr(key),
}}
/>
)
return (
<CardThemed>
<CardContent>
<Stack spacing={1}>
{[...baseKeys, ...statKeys].map((key) => (
<NumberInputLazy
key={key}
value={baseStats[key] || 0}
onChange={(v) =>
setBaseStats({
...baseStats,
[key]: v,
})
}
inputProps={{ sx: { textAlign: 'right' } }}
InputProps={{
startAdornment: key,
endAdornment: getUnitStr(key),
}}
/>
))}
</Stack>
<Typography variant="h6">Character</Typography>
<LocationAutocomplete locKey={location} setLocKey={setLocation} />
<Typography>Character Base Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{baseKeys.map((key) => input(key))}
</Box>
<Typography>Character Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{statKeys.map((key) => input(key))}
</Box>
<Typography>Enemy Stats</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{enemyKeys.map((key) => input(key))}
</Box>
<Typography>Combat Buffs(Unconditonal)</Typography>
<Box sx={{ display: 'flex', gap: 1, pb: 2, flexWrap: 'wrap' }}>
{unCondKeys.map((key) => input(key))}
</Box>
</CardContent>
</CardThemed>
)
Expand Down
Loading
Loading