Merge pull request #155 from jedmund/perpetuity
Add indicators for Perpetuity Ring to CharacterUnit
This commit is contained in:
commit
f8e6a4d26b
6 changed files with 247 additions and 69 deletions
|
|
@ -41,28 +41,17 @@ import CrossIcon from '~public/icons/Cross.svg'
|
|||
import './index.scss'
|
||||
|
||||
// Types
|
||||
import { CharacterOverMastery, ExtendedMastery } from '~types'
|
||||
|
||||
interface GridCharacterObject {
|
||||
character: {
|
||||
ring1: ExtendedMastery
|
||||
ring2: ExtendedMastery
|
||||
ring3: ExtendedMastery
|
||||
ring4: ExtendedMastery
|
||||
earring: ExtendedMastery
|
||||
awakening: {
|
||||
type?: number
|
||||
level?: number
|
||||
}
|
||||
transcendence_step: number
|
||||
perpetuity: boolean
|
||||
}
|
||||
}
|
||||
import {
|
||||
CharacterOverMastery,
|
||||
ExtendedMastery,
|
||||
GridCharacterObject,
|
||||
} from '~types'
|
||||
|
||||
interface Props {
|
||||
gridCharacter: GridCharacter
|
||||
open: boolean
|
||||
onOpenChange: (open: boolean) => void
|
||||
updateCharacter: (object: GridCharacterObject) => Promise<any>
|
||||
}
|
||||
|
||||
const CharacterModal = ({
|
||||
|
|
@ -70,6 +59,7 @@ const CharacterModal = ({
|
|||
children,
|
||||
open: modalOpen,
|
||||
onOpenChange,
|
||||
updateCharacter,
|
||||
}: PropsWithChildren<Props>) => {
|
||||
const router = useRouter()
|
||||
const locale =
|
||||
|
|
@ -133,42 +123,6 @@ const CharacterModal = ({
|
|||
setPerpetuity(gridCharacter.perpetuity)
|
||||
}, [gridCharacter])
|
||||
|
||||
// Methods: UI state management
|
||||
function handleOpenChange(open: boolean) {
|
||||
setOpen(open)
|
||||
onOpenChange(open)
|
||||
}
|
||||
|
||||
// Methods: Receive data from components
|
||||
function receiveRingValues(overMastery: CharacterOverMastery) {
|
||||
setRings(overMastery)
|
||||
}
|
||||
|
||||
function receiveEarringValues(
|
||||
earringModifier: number,
|
||||
earringStrength: number
|
||||
) {
|
||||
setEarring({
|
||||
modifier: earringModifier,
|
||||
strength: earringStrength,
|
||||
})
|
||||
}
|
||||
|
||||
function handleCheckedChange(checked: boolean) {
|
||||
setPerpetuity(checked)
|
||||
}
|
||||
|
||||
function receiveAwakeningValues(type: number, level: number) {
|
||||
setAwakeningType(type)
|
||||
setAwakeningLevel(level)
|
||||
}
|
||||
|
||||
function receiveValidity(isValid: boolean) {
|
||||
setFormValid(isValid)
|
||||
}
|
||||
|
||||
// Methods: Data syncing
|
||||
|
||||
// Prepare the GridWeaponObject to send to the server
|
||||
function prepareObject() {
|
||||
let object: GridCharacterObject = {
|
||||
|
|
@ -205,27 +159,45 @@ const CharacterModal = ({
|
|||
return object
|
||||
}
|
||||
|
||||
// Send the GridWeaponObject to the server
|
||||
async function updateCharacter() {
|
||||
const updateObject = prepareObject()
|
||||
|
||||
return await api.endpoints.grid_characters
|
||||
.update(gridCharacter.id, updateObject)
|
||||
.then((response) => processResult(response))
|
||||
.catch((error) => processError(error))
|
||||
// Methods: UI state management
|
||||
function handleOpenChange(open: boolean) {
|
||||
setOpen(open)
|
||||
onOpenChange(open)
|
||||
}
|
||||
|
||||
// Save the server's response to state
|
||||
function processResult(response: AxiosResponse) {
|
||||
const gridCharacter: GridCharacter = response.data
|
||||
appState.grid.characters[gridCharacter.position] = gridCharacter
|
||||
// Methods: Receive data from components
|
||||
function receiveRingValues(overMastery: CharacterOverMastery) {
|
||||
setRings(overMastery)
|
||||
}
|
||||
|
||||
function receiveEarringValues(
|
||||
earringModifier: number,
|
||||
earringStrength: number
|
||||
) {
|
||||
setEarring({
|
||||
modifier: earringModifier,
|
||||
strength: earringStrength,
|
||||
})
|
||||
}
|
||||
|
||||
function handleCheckedChange(checked: boolean) {
|
||||
setPerpetuity(checked)
|
||||
}
|
||||
|
||||
async function handleUpdateCharacter() {
|
||||
await updateCharacter(prepareObject())
|
||||
|
||||
setOpen(false)
|
||||
if (onOpenChange) onOpenChange(false)
|
||||
}
|
||||
|
||||
function processError(error: any) {
|
||||
console.error(error)
|
||||
function receiveAwakeningValues(type: number, level: number) {
|
||||
setAwakeningType(type)
|
||||
setAwakeningLevel(level)
|
||||
}
|
||||
|
||||
function receiveValidity(isValid: boolean) {
|
||||
setFormValid(isValid)
|
||||
}
|
||||
|
||||
const ringSelect = () => {
|
||||
|
|
@ -322,7 +294,7 @@ const CharacterModal = ({
|
|||
<div className="DialogFooter" ref={footerRef}>
|
||||
<Button
|
||||
contained={true}
|
||||
onClick={updateCharacter}
|
||||
onClick={handleUpdateCharacter}
|
||||
disabled={!formValid}
|
||||
text={t('modals.characters.buttons.confirm')}
|
||||
/>
|
||||
|
|
|
|||
|
|
@ -97,4 +97,34 @@
|
|||
font-size: $font-tiny;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover .Perpetuity.Empty {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.Perpetuity {
|
||||
position: absolute;
|
||||
background-image: url('/icons/perpetuity/filled.svg');
|
||||
background-size: $unit-4x $unit-4x;
|
||||
z-index: 20;
|
||||
top: $unit * -1;
|
||||
right: $unit-3x;
|
||||
width: $unit-4x;
|
||||
height: $unit-4x;
|
||||
transition: $duration-zoom opacity ease-in-out;
|
||||
|
||||
&:hover {
|
||||
background-image: url('/icons/perpetuity/empty.svg');
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&.Empty {
|
||||
background-image: url('/icons/perpetuity/empty.svg');
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
background-image: url('/icons/perpetuity/filled.svg');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import React, { MouseEvent, useEffect, useState } from 'react'
|
|||
import { useRouter } from 'next/router'
|
||||
import { useSnapshot } from 'valtio'
|
||||
import { Trans, useTranslation } from 'next-i18next'
|
||||
import { AxiosResponse } from 'axios'
|
||||
import classNames from 'classnames'
|
||||
|
||||
import Alert from '~components/Alert'
|
||||
|
|
@ -17,12 +18,18 @@ import ContextMenuItem from '~components/ContextMenuItem'
|
|||
import SearchModal from '~components/SearchModal'
|
||||
import UncapIndicator from '~components/UncapIndicator'
|
||||
|
||||
import api from '~utils/api'
|
||||
import { appState } from '~utils/appState'
|
||||
|
||||
import PlusIcon from '~public/icons/Add.svg'
|
||||
import SettingsIcon from '~public/icons/Settings.svg'
|
||||
|
||||
import type { SearchableObject } from '~types'
|
||||
// Types
|
||||
import type {
|
||||
GridCharacterObject,
|
||||
PerpetuityObject,
|
||||
SearchableObject,
|
||||
} from '~types'
|
||||
|
||||
import './index.scss'
|
||||
|
||||
|
|
@ -99,6 +106,16 @@ const CharacterUnit = ({
|
|||
setContextMenuOpen(!contextMenuOpen)
|
||||
}
|
||||
|
||||
function handlePerpetuityClick() {
|
||||
if (gridCharacter) {
|
||||
let object: PerpetuityObject = {
|
||||
character: { perpetuity: !gridCharacter.perpetuity },
|
||||
}
|
||||
|
||||
updateCharacter(object)
|
||||
}
|
||||
}
|
||||
|
||||
// Methods: Handle open change
|
||||
function handleCharacterModalOpenChange(open: boolean) {
|
||||
setDetailsModalOpen(open)
|
||||
|
|
@ -113,6 +130,28 @@ const CharacterUnit = ({
|
|||
}
|
||||
|
||||
// Methods: Mutate data
|
||||
|
||||
// Send the GridWeaponObject to the server
|
||||
async function updateCharacter(
|
||||
object: GridCharacterObject | PerpetuityObject
|
||||
) {
|
||||
if (gridCharacter)
|
||||
return await api.endpoints.grid_characters
|
||||
.update(gridCharacter.id, object)
|
||||
.then((response) => processResult(response))
|
||||
.catch((error) => processError(error))
|
||||
}
|
||||
|
||||
// Save the server's response to state
|
||||
function processResult(response: AxiosResponse) {
|
||||
const gridCharacter: GridCharacter = response.data
|
||||
appState.grid.characters[gridCharacter.position] = gridCharacter
|
||||
}
|
||||
|
||||
function processError(error: any) {
|
||||
console.error(error)
|
||||
}
|
||||
|
||||
function passUncapData(uncap: number) {
|
||||
if (gridCharacter) updateUncap(gridCharacter.id, position, uncap)
|
||||
}
|
||||
|
|
@ -160,6 +199,7 @@ const CharacterUnit = ({
|
|||
gridCharacter={gridCharacter}
|
||||
open={detailsModalOpen}
|
||||
onOpenChange={handleCharacterModalOpenChange}
|
||||
updateCharacter={updateCharacter}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
|
@ -228,6 +268,17 @@ const CharacterUnit = ({
|
|||
}
|
||||
|
||||
// Methods: Core element rendering
|
||||
const perpetuity = () => {
|
||||
if (gridCharacter) {
|
||||
const classes = classNames({
|
||||
Perpetuity: true,
|
||||
Empty: !gridCharacter.perpetuity,
|
||||
})
|
||||
|
||||
return <i className={classes} onClick={handlePerpetuityClick} />
|
||||
}
|
||||
}
|
||||
|
||||
const image = (
|
||||
<div className="CharacterImage" onClick={openSearchModal}>
|
||||
<img
|
||||
|
|
@ -249,6 +300,7 @@ const CharacterUnit = ({
|
|||
<>
|
||||
<div className={classes}>
|
||||
{contextMenu()}
|
||||
{perpetuity()}
|
||||
{image}
|
||||
{gridCharacter && character ? (
|
||||
<UncapIndicator
|
||||
|
|
|
|||
49
public/icons/perpetuity/empty.svg
Normal file
49
public/icons/perpetuity/empty.svg
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
<svg viewBox="0 0 45 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_1460_2996)">
|
||||
<rect x="4" y="2" width="37" height="38" rx="2" fill="white"/>
|
||||
<rect x="5" y="3" width="35" height="36" rx="1" fill="url(#paint0_linear_1460_2996)"/>
|
||||
<g filter="url(#filter1_i_1460_2996)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.4885 18.3682C27.4659 19.17 29.6429 21.7269 29.6429 24.7572C29.6429 28.4299 26.445 31.4072 22.5001 31.4072C18.5552 31.4072 15.3572 28.4299 15.3572 24.7572C15.3572 21.7288 17.5316 19.1732 20.5061 18.3697L18.6119 16.002C15.0204 17.4432 12.5 20.8206 12.5 24.7572C12.5 30.0039 16.9772 34.2572 22.5 34.2572C28.0228 34.2572 32.5 30.0039 32.5 24.7572C32.5 20.8187 29.9772 17.4401 26.3831 16L24.4885 18.3682Z" fill="#999999"/>
|
||||
</g>
|
||||
<g filter="url(#filter2_i_1460_2996)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7158 18.0239L16.9691 12.0905C16.6896 11.7412 16.6762 11.2487 16.9363 10.8846L18.6976 8.41876C18.8853 8.15597 19.1884 8 19.5113 8H25.4821C25.805 8 26.1081 8.15597 26.2958 8.41876L28.0571 10.8846C28.3172 11.2487 28.3038 11.7412 28.0243 12.0905L23.2776 18.0239C22.8772 18.5243 22.1162 18.5243 21.7158 18.0239ZM23 9.25V15.7873C23 16.0236 23.2976 16.128 23.4452 15.9435L26.8751 11.6562C26.9481 11.5649 26.9481 11.4351 26.8751 11.3438L25.0751 9.09383C25.0276 9.03452 24.9558 9 24.8798 9H23.25C23.1119 9 23 9.11193 23 9.25Z" fill="#999999"/>
|
||||
</g>
|
||||
<rect x="5.5" y="3.5" width="34" height="35" rx="0.5" stroke="black" stroke-opacity="0.09"/>
|
||||
<rect x="3.5" y="1.5" width="38" height="39" rx="2.5" stroke="black" stroke-opacity="0.1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_1460_2996" x="0" y="0" width="45" height="46" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="2"/>
|
||||
<feGaussianBlur stdDeviation="1.5"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.13 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1460_2996"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1460_2996" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter1_i_1460_2996" x="12.5" y="16" width="20" height="19.2572" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="1"/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1460_2996"/>
|
||||
</filter>
|
||||
<filter id="filter2_i_1460_2996" x="16.75" y="8" width="11.4934" height="11.3992" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="1"/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.12 0"/>
|
||||
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_1460_2996"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_1460_2996" x1="22.5" y1="3" x2="22.5" y2="39" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.0618126" stop-color="#C1C1C1"/>
|
||||
<stop offset="0.756271" stop-color="#B0B0B0"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 3.8 KiB |
53
public/icons/perpetuity/filled.svg
Normal file
53
public/icons/perpetuity/filled.svg
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
<svg viewBox="0 0 45 46" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g filter="url(#filter0_d_1460_2995)">
|
||||
<rect x="4" y="2" width="37" height="38" rx="2" fill="white"/>
|
||||
<rect x="5" y="3" width="35" height="36" rx="1" fill="url(#paint0_linear_1460_2995)"/>
|
||||
<g filter="url(#filter1_d_1460_2995)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M24.4885 18.3682C27.4659 19.17 29.6429 21.7269 29.6429 24.7572C29.6429 28.4299 26.445 31.4072 22.5001 31.4072C18.5552 31.4072 15.3572 28.4299 15.3572 24.7572C15.3572 21.7288 17.5316 19.1732 20.5061 18.3697L18.6119 16.002C15.0204 17.4432 12.5 20.8206 12.5 24.7572C12.5 30.0039 16.9772 34.2572 22.5 34.2572C28.0228 34.2572 32.5 30.0039 32.5 24.7572C32.5 20.8187 29.9772 17.4401 26.3831 16L24.4885 18.3682Z" fill="white"/>
|
||||
</g>
|
||||
<g filter="url(#filter2_d_1460_2995)">
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.7158 18.0239L16.9691 12.0905C16.6896 11.7412 16.6762 11.2487 16.9363 10.8846L18.6976 8.41876C18.8853 8.15597 19.1884 8 19.5113 8H25.4821C25.805 8 26.1081 8.15597 26.2958 8.41876L28.0571 10.8846C28.3172 11.2487 28.3038 11.7412 28.0243 12.0905L23.2776 18.0239C22.8772 18.5243 22.1162 18.5243 21.7158 18.0239ZM23 9.25V15.7873C23 16.0236 23.2976 16.128 23.4452 15.9435L26.8751 11.6562C26.9481 11.5649 26.9481 11.4351 26.8751 11.3438L25.0751 9.09383C25.0276 9.03452 24.9558 9 24.8798 9H23.25C23.1119 9 23 9.11193 23 9.25Z" fill="white"/>
|
||||
</g>
|
||||
<rect x="5.5" y="3.5" width="34" height="35" rx="0.5" stroke="url(#paint1_linear_1460_2995)" stroke-opacity="0.5"/>
|
||||
<rect x="3.5" y="1.5" width="38" height="39" rx="2.5" stroke="black" stroke-opacity="0.1"/>
|
||||
</g>
|
||||
<defs>
|
||||
<filter id="filter0_d_1460_2995" x="0" y="0" width="45" height="46" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="2"/>
|
||||
<feGaussianBlur stdDeviation="1.5"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.13 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1460_2995"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1460_2995" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter1_d_1460_2995" x="10.5" y="15" width="24" height="22.2572" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="1"/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.22 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1460_2995"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1460_2995" result="shape"/>
|
||||
</filter>
|
||||
<filter id="filter2_d_1460_2995" x="14.75" y="7" width="15.4934" height="14.3992" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
|
||||
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
|
||||
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
|
||||
<feOffset dy="1"/>
|
||||
<feGaussianBlur stdDeviation="1"/>
|
||||
<feComposite in2="hardAlpha" operator="out"/>
|
||||
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.22 0"/>
|
||||
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_1460_2995"/>
|
||||
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_1460_2995" result="shape"/>
|
||||
</filter>
|
||||
<linearGradient id="paint0_linear_1460_2995" x1="22.5" y1="3" x2="22.5" y2="39" gradientUnits="userSpaceOnUse">
|
||||
<stop offset="0.0618126" stop-color="#6CD6FF"/>
|
||||
<stop offset="0.756271" stop-color="#ACB3FE"/>
|
||||
</linearGradient>
|
||||
<linearGradient id="paint1_linear_1460_2995" x1="22.5" y1="3" x2="22.5" y2="39" gradientUnits="userSpaceOnUse">
|
||||
<stop stop-color="#8DEFFE"/>
|
||||
<stop offset="1" stop-color="#E8EDFF"/>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 4 KiB |
22
types/index.d.ts
vendored
22
types/index.d.ts
vendored
|
|
@ -48,3 +48,25 @@ export type CharacterOverMastery = {
|
|||
3: ExtendedMastery
|
||||
4: ExtendedMastery
|
||||
}
|
||||
|
||||
interface GridCharacterObject {
|
||||
character: {
|
||||
ring1: ExtendedMastery
|
||||
ring2: ExtendedMastery
|
||||
ring3: ExtendedMastery
|
||||
ring4: ExtendedMastery
|
||||
earring: ExtendedMastery
|
||||
awakening: {
|
||||
type?: number
|
||||
level?: number
|
||||
}
|
||||
transcendence_step: number
|
||||
perpetuity: boolean
|
||||
}
|
||||
}
|
||||
|
||||
interface PerpetuityObject {
|
||||
character: {
|
||||
perpetuity: boolean
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue