Add support for weapon transcendence (#402)

This commit is contained in:
Justin Edmund 2024-01-15 14:16:49 -08:00 committed by GitHub
parent acf9773f38
commit 3b6cc5ba65
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 195 additions and 48 deletions

View file

@ -77,7 +77,7 @@ const HovercardHeader = ({ gridObject, object, type, ...props }: Props) => {
) {
suffix = '_02'
} else if (
gridSummon.object.uncap.xlb &&
gridSummon.object.uncap.transcendence &&
gridSummon.transcendence_step > 0
) {
suffix = '_03'

View file

@ -17,6 +17,7 @@ interface Props {
removeWeapon: (id: string) => void
updateObject: (object: SearchableObject, position: number) => void
updateUncap: (id: string, position: number, uncap: number) => void
updateTranscendence: (id: string, position: number, stage: number) => void
}
// Constants
@ -29,6 +30,7 @@ const ExtraWeaponsGrid = ({
removeWeapon,
updateObject,
updateUncap,
updateTranscendence,
}: Props) => {
return (
<ul className={styles.grid}>
@ -47,6 +49,7 @@ const ExtraWeaponsGrid = ({
removeWeapon={removeWeapon}
updateObject={updateObject}
updateUncap={updateUncap}
updateTranscendence={updateTranscendence}
/>
</li>
)

View file

@ -318,7 +318,7 @@ const GridRep = ({ party, loading, onClick, onSave }: Props) => {
if (summon) {
// Change the image based on the uncap level
let suffix = ''
if (summon.object.uncap.xlb && summon.uncap_level == 6) {
if (summon.object.uncap.transcendence && summon.uncap_level == 6) {
if (summon.transcendence_step >= 1 && summon.transcendence_step < 5) {
suffix = '_03'
} else if (summon.transcendence_step === 5) {
@ -363,7 +363,10 @@ const GridRep = ({ party, loading, onClick, onSave }: Props) => {
if (summon && gridSummon) {
// Change the image based on the uncap level
let suffix = ''
if (gridSummon.object.uncap.xlb && gridSummon.uncap_level == 6) {
if (
<gridSummon className="object uncap transc"></gridSummon> &&
gridSummon.uncap_level == 6
) {
if (
gridSummon.transcendence_step >= 1 &&
gridSummon.transcendence_step < 5

View file

@ -70,7 +70,10 @@ const SummonRep = (props: Props) => {
if (mainSummon) {
// Change the image based on the uncap level
let suffix = ''
if (mainSummon.object.uncap.xlb && mainSummon.uncap_level == 6) {
if (
mainSummon.object.uncap.transcendence &&
mainSummon.uncap_level == 6
) {
if (
mainSummon.transcendence_step >= 1 &&
mainSummon.transcendence_step < 5
@ -123,7 +126,10 @@ const SummonRep = (props: Props) => {
if (summon && gridSummon) {
// Change the image based on the uncap level
let suffix = ''
if (gridSummon.object.uncap.xlb && gridSummon.uncap_level == 6) {
if (
gridSummon.object.uncap.transcendence &&
gridSummon.uncap_level == 6
) {
if (
gridSummon.transcendence_step >= 1 &&
gridSummon.transcendence_step < 5

View file

@ -60,7 +60,7 @@ const SummonHovercard = (props: Props) => {
) {
suffix = '_02'
} else if (
props.gridSummon.object.uncap.xlb &&
props.gridSummon.object.uncap.transcendence &&
props.gridSummon.transcendence_step > 0
) {
suffix = '_03'

View file

@ -177,7 +177,10 @@ const SummonUnit = ({
]
let suffix = ''
if (gridSummon.object.uncap.xlb && gridSummon.uncap_level == 6) {
if (
gridSummon.object.uncap.transcendence &&
gridSummon.uncap_level == 6
) {
if (
gridSummon.transcendence_step >= 1 &&
gridSummon.transcendence_step < 5
@ -320,12 +323,12 @@ const SummonUnit = ({
{contextMenu()}
{quickSummon()}
{image()}
{gridSummon ? (
{gridSummon && (
<UncapIndicator
type="summon"
ulb={gridSummon.object.uncap.ulb || false}
flb={gridSummon.object.uncap.flb || false}
xlb={gridSummon.object.uncap.xlb || false}
transcendence={gridSummon.object.uncap.transcendence || false}
editable={editable}
uncapLevel={gridSummon.uncap_level}
transcendenceStage={gridSummon.transcendence_step}
@ -334,8 +337,6 @@ const SummonUnit = ({
updateTranscendence={passTranscendenceData}
special={false}
/>
) : (
''
)}
<h3 className={styles.name}>{summon?.name[locale]}</h3>
</div>

View file

@ -16,7 +16,7 @@ interface Props
React.DialogHTMLAttributes<HTMLDivElement>,
HTMLDivElement
> {
type: 'character' | 'summon'
type: 'character' | 'summon' | 'weapon'
starRef: React.RefObject<HTMLDivElement>
open: boolean
stage: number
@ -56,7 +56,7 @@ const TranscendencePopover = ({
useEffect(() => {
if (type === 'character') setBaseLevel(100)
else if (type === 'summon') setBaseLevel(200)
else if (['weapon', 'summon'].includes(type)) setBaseLevel(200)
}, [type])
function handleFragmentClicked(newStage: number) {

View file

@ -15,7 +15,7 @@ interface Props extends React.ComponentProps<'div'> {
editable: boolean
flb: boolean
ulb: boolean
xlb?: boolean
transcendence?: boolean
special: boolean
updateUncap?: (index: number) => void
updateTranscendence?: (index: number) => void
@ -57,7 +57,7 @@ const UncapIndicator = (props: Props) => {
}
}
} else {
if (props.xlb) {
if (props.transcendence) {
numStars = 6
} else if (props.ulb) {
numStars = 5
@ -93,7 +93,7 @@ const UncapIndicator = (props: Props) => {
const transcendence = (i: number) => {
const tabIndex = props.position ? props.position * 7 + i + 1 : 0
return props.type === 'character' || props.type === 'summon' ? (
return (
<TranscendencePopover
open={popoverOpen}
stage={props.transcendenceStage || 0}
@ -113,14 +113,6 @@ const UncapIndicator = (props: Props) => {
onStarClick={handleStarClicked}
/>
</TranscendencePopover>
) : (
<TranscendenceStar
key={`star_${i}`}
stage={props.transcendenceStage || 0}
editable={props.editable}
interactive={false}
tabIndex={tabIndex}
/>
)
}
@ -165,25 +157,33 @@ const UncapIndicator = (props: Props) => {
)
}
const renderStar = (i: number) => {
if (props.type === 'weapon' && i > 4) {
return transcendence(i)
}
if (props.type === 'character' && i > 4) {
return props.special ? ulb(i) : transcendence(i)
}
if (props.type === 'summon' && i > 4) {
return transcendence(i)
}
if (
(props.special && props.type === 'character' && i === 3) ||
(props.type === 'character' && i === 4) ||
(props.type !== 'character' && i > 2)
) {
return flb(i)
}
return mlb(i)
}
return (
<div className={classes}>
<ul className={styles.indicator}>
{Array.from(Array(numStars)).map((x, i) => {
if (props.type === 'character' && i > 4) {
if (props.special) return ulb(i)
else return transcendence(i)
} else if (props.type === 'summon' && i > 4) {
return transcendence(i)
} else if (
(props.special && props.type === 'character' && i == 3) ||
(props.type === 'character' && i == 4) ||
(props.type !== 'character' && i > 2)
) {
return flb(i)
} else {
return mlb(i)
}
})}
{Array.from(Array(numStars)).map((_, i) => renderStar(i))}
</ul>
</div>
)

View file

@ -65,6 +65,10 @@ const WeaponGrid = (props: Props) => {
const [previousUncapValues, setPreviousUncapValues] = useState<{
[key: number]: number
}>({})
const [previousTranscendenceStages, setPreviousTranscendenceStages] =
useState<{
[key: number]: number
}>({})
// Initialize an array of current uncap values for each weapon
useEffect(() => {
@ -90,13 +94,16 @@ const WeaponGrid = (props: Props) => {
const payload: DetailsObject = { extra: party.extra }
props.createParty(payload).then((team) => {
saveWeapon(team.id, weapon, position).then((response) => {
if (response) storeGridWeapon(response.data.grid_weapon)
if (response && response.data.grid_weapon) {
storeGridWeapon(response.data.grid_weapon)
}
})
})
} else {
if (props.editable)
saveWeapon(party.id, weapon, position)
.then((response) => {
console.log(response)
if (response) handleWeaponResponse(response.data)
})
.catch((error) => {
@ -135,7 +142,12 @@ const WeaponGrid = (props: Props) => {
if (data.position) setPosition(data.position)
setModalOpen(true)
} else {
storeGridWeapon(data.grid_weapon)
if (data.grid_weapon) {
storeGridWeapon(data.grid_weapon)
} else {
console.error('No grid weapon returned')
console.log(data)
}
// If we replaced an existing weapon, remove it from the grid
if (data.hasOwnProperty('meta') && data.meta['replaced'] !== undefined) {
@ -217,7 +229,12 @@ const WeaponGrid = (props: Props) => {
})
// Store new character in state
storeGridWeapon(response.data.grid_weapon)
if (response.data.grid_weapon)
storeGridWeapon(response.data.grid_weapon)
else {
console.error('No grid weapon returned')
console.log(response.data)
}
// Reset conflict
resetConflict()
@ -335,6 +352,110 @@ const WeaponGrid = (props: Props) => {
setPreviousUncapValues(newPreviousValues)
}
// Methods: Updating transcendence stage
// Note: Saves, but debouncing is not working properly
async function saveTranscendence(
id: string,
position: number,
stage: number
) {
storePreviousUncapValue(position)
storePreviousTranscendenceStage(position)
const payload = {
weapon: {
uncap_level: stage > 0 ? 6 : 5,
transcendence_step: stage,
},
}
try {
if (stage != previousTranscendenceStages[position])
await api.updateTranscendence('weapon', id, stage).then((response) => {
storeGridWeapon(response.data.grid_weapon)
})
} catch (error) {
console.error(error)
// Revert optimistic UI
updateUncapLevel(position, previousUncapValues[position])
updateTranscendenceStage(position, previousTranscendenceStages[position])
// Remove optimistic key
let newPreviousTranscendenceStages = { ...previousTranscendenceStages }
let newPreviousUncapValues = { ...previousUncapValues }
delete newPreviousTranscendenceStages[position]
delete newPreviousUncapValues[position]
setPreviousTranscendenceStages(newPreviousTranscendenceStages)
setPreviousUncapValues(newPreviousUncapValues)
}
}
function initiateTranscendenceUpdate(
id: string,
position: number,
stage: number
) {
if (props.editable) {
memoizeTranscendenceAction(id, position, stage)
// Optimistically update UI
updateTranscendenceStage(position, stage)
if (stage > 0) {
updateUncapLevel(position, 6)
}
}
}
const memoizeTranscendenceAction = useCallback(
(id: string, position: number, stage: number) => {
debouncedTranscendenceAction(id, position, stage)
},
[props, previousTranscendenceStages]
)
const debouncedTranscendenceAction = useMemo(
() =>
debounce((id, position, number) => {
saveTranscendence(id, position, number)
}, 500),
[props, saveTranscendence]
)
const updateTranscendenceStage = (position: number, stage: number) => {
// console.log(`Updating uncap level at position ${position} to ${uncapLevel}`)
if (appState.grid.weapons.mainWeapon && position == -1)
appState.grid.weapons.mainWeapon.transcendence_step = stage
else {
const weapon = appState.grid.weapons.allWeapons[position]
if (weapon) {
weapon.transcendence_step = stage
appState.grid.weapons.allWeapons[position] = weapon
}
}
}
function storePreviousTranscendenceStage(position: number) {
// Save the current value in case of an unexpected result
let newPreviousValues = { ...previousUncapValues }
if (appState.grid.weapons.mainWeapon && position == -1) {
newPreviousValues[position] = appState.grid.weapons.mainWeapon.uncap_level
} else {
const weapon = appState.grid.weapons.allWeapons[position]
if (weapon) {
newPreviousValues[position] = weapon.uncap_level
} else {
newPreviousValues[position] = 0
}
}
setPreviousUncapValues(newPreviousValues)
}
// Methods: Convenience
const displayExtraContainer =
props.editable ||
@ -352,6 +473,7 @@ const WeaponGrid = (props: Props) => {
removeWeapon={removeWeapon}
updateObject={receiveWeaponFromSearch}
updateUncap={initiateUncapUpdate}
updateTranscendence={initiateTranscendenceUpdate}
/>
)
@ -370,6 +492,7 @@ const WeaponGrid = (props: Props) => {
removeWeapon={removeWeapon}
updateObject={receiveWeaponFromSearch}
updateUncap={initiateUncapUpdate}
updateTranscendence={initiateTranscendenceUpdate}
/>
</li>
)
@ -388,6 +511,7 @@ const WeaponGrid = (props: Props) => {
removeWeapon={removeWeapon}
updateObject={receiveWeaponFromSearch}
updateUncap={initiateUncapUpdate}
updateTranscendence={initiateTranscendenceUpdate}
/>
)}
</ExtraContainerItem>

View file

@ -37,6 +37,7 @@ interface Props {
removeWeapon: (id: string) => void
updateObject: (object: SearchableObject, position: number) => void
updateUncap: (id: string, position: number, uncap: number) => void
updateTranscendence: (id: string, position: number, stage: number) => void
}
const WeaponUnit = ({
@ -47,6 +48,7 @@ const WeaponUnit = ({
removeWeapon: sendWeaponToRemove,
updateObject,
updateUncap,
updateTranscendence,
}: Props) => {
// Translations and locale
const { t } = useTranslation('common')
@ -130,6 +132,10 @@ const WeaponUnit = ({
if (gridWeapon) updateUncap(gridWeapon.id, position, index)
}
function passTranscendenceData(stage: number) {
if (gridWeapon) updateTranscendence(gridWeapon.id, position, stage)
}
function removeWeapon() {
if (gridWeapon) sendWeaponToRemove(gridWeapon.id)
setAlertOpen(false)
@ -559,18 +565,20 @@ const WeaponUnit = ({
<div className={classes}>
{contextMenu()}
{image()}
{gridWeapon && weapon ? (
{gridWeapon && (
<UncapIndicator
type="weapon"
ulb={gridWeapon.object.uncap.ulb || false}
flb={gridWeapon.object.uncap.flb || false}
transcendence={gridWeapon.object.uncap.transcendence || false}
editable={editable}
uncapLevel={gridWeapon.uncap_level}
transcendenceStage={gridWeapon.transcendence_step}
position={gridWeapon.position}
updateUncap={passUncapData}
updateTranscendence={passTranscendenceData}
special={false}
/>
) : (
''
)}
<h3 className={styles.name}>{weapon?.name[locale]}</h3>
</div>

View file

@ -4,6 +4,7 @@ interface GridWeapon {
position: number
object: Weapon
uncap_level: number
transcendence_step: number
element: number
weapon_keys?: Array<WeaponKey>
ax?: Array<SimpleAxSkill>

2
types/Summon.d.ts vendored
View file

@ -27,7 +27,7 @@ interface Summon {
uncap: {
flb: boolean
ulb: boolean
xlb: boolean
transcendence: boolean
}
position?: number
}

1
types/Weapon.d.ts vendored
View file

@ -32,6 +32,7 @@ interface Weapon {
uncap: {
flb: boolean
ulb: boolean
transcendence: boolean
}
position?: number
}

View file

@ -184,7 +184,7 @@ class Api {
})
}
updateTranscendence(resource: 'character'|'summon', id: string, value: number) {
updateTranscendence(resource: 'character'|'summon'|'weapon', id: string, value: number) {
const pluralized = resource + 's'
const resourceUrl = `${this.url}/${pluralized}/update_uncap`
return axios.post(resourceUrl, {