Add weapon page

This commit is contained in:
Sakura Knoll
2023-07-10 23:32:11 +09:00 Unverified
parent a1c4d16264
commit 4c875ecb8b
15 changed files with 377 additions and 37 deletions
Binary file not shown.

After

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

+1 -1
View File
@@ -34,7 +34,7 @@ function adjustColor(color: unknown): string | undefined {
const normalizedColor = color.toUpperCase() const normalizedColor = color.toUpperCase()
if (normalizedColor.startsWith('#FEDF4C')) { if (normalizedColor.startsWith('#FEDF4C')) {
return '#e6c010' return '#d1af15'
} }
if (normalizedColor.startsWith('#FFC741')) { if (normalizedColor.startsWith('#FFC741')) {
+59
View File
@@ -0,0 +1,59 @@
import { Box, Flex } from 'theme-ui'
import { assetsBucketBaseUrl } from '../../lib/consts'
import { repeat } from '../../lib/utils'
interface WeaponIconProps {
icon: string
rarity?: number
}
const starSize = 16
const WeaponIcon = ({ icon: fileName, rarity }: WeaponIconProps) => {
return (
<Box sx={{ width: 112 }}>
<Box
sx={{
borderRadius: 4,
width: (128 / 8) * 7,
height: (112 / 8) * 7,
background: ` no-repeat 100% 100% /100% url(${assetsBucketBaseUrl}/raw/weaponicons/${fileName}.png), ${getBackgroundByRarity(
rarity
)}`
}}
/>
{rarity != null && (
<Flex sx={{ marginTop: -starSize / 2, justifyContent: 'center', width: '100%' }}>
{repeat(rarity, index => (
<Box
key={index}
sx={{
width: starSize,
height: starSize,
background: `no-repeat 50% / 100% url(${assetsBucketBaseUrl}/raw-misc/StarBig.png)`
}}
/>
))}
</Flex>
)}
</Box>
)
}
export default WeaponIcon
function getBackgroundByRarity(rarity?: number) {
switch (rarity) {
case 6:
return 'linear-gradient(180deg, #e18434, #fbd977)'
case 5:
return 'linear-gradient(transparent, #c86de0),#7630a3'
case 4:
case 3:
return 'linear-gradient(transparent, #0ec1eb), #2368b1'
case 2:
return `linear-gradient(transparent, #52c389),#31756c`
default:
return 'transparent'
}
}
+7
View File
@@ -0,0 +1,7 @@
export function repeat<N>(count: number, rendererFn: (index: number) => N) {
const result: Array<N> = []
for (let i = 0; i < count; i++) {
result.push(rendererFn(i))
}
return result
}
+37 -26
View File
@@ -146,39 +146,44 @@ export interface BattlesuitSubSkill {
export interface WeaponCatalogItem { export interface WeaponCatalogItem {
id: string id: string
name: string name: string
icon: string
type: WeaponType type: WeaponType
maxRarity: 1 | 2 | 3 | 4 | 5 maxRarity: 1 | 2 | 3 | 4 | 5 | 6
}
export interface RootWeaponData {
id: string
weapons: WeaponData[]
} }
export interface WeaponData { export interface WeaponData {
id: string id: string
weapons: { rarity: 1 | 2 | 3 | 4 | 5 | 6
maxLv: number
type: WeaponType
name: string
description: string
icon: string
hpBase: number
hpAdd: number
spBase: number
spAdd: number
attackBase: number
attackAdd: number
defenceBase: number
defenceAdd: number
criticalBase: number
criticalAdd: number
resistanceBase: number
resistanceAdd: number
skills: WeaponSkill[]
rankUpMaterials: {
id: string id: string
rarity: number amount: number
maxLv: number }[]
type: WeaponType powerType: number
title: string
description: string
icon: string
hpBase: number
hpAdd: number
spBase: number
spAdd: number
attackBase: number
attackAdd: number
defenceBase: number
defenceAdd: number
criticalBase: number
criticalAdd: number
resistanceBase: number
resistanceAdd: number
skills: WeaponSkill[]
rankUpMaterials: {
id: string
amount: number
}[]
}
} }
export interface WeaponSkill { export interface WeaponSkill {
id: string id: string
name: string name: string
@@ -191,4 +196,10 @@ export interface WeaponSkill {
type: TagType type: TagType
comment: string comment: string
}[] }[]
param1: number
param1Add: number
param2: number
param2Add: number
param3: number
param3Add: number
} }
@@ -15,7 +15,7 @@ describe('compileWeaponData', () => {
]) ])
}) })
expect(targetItem!.weapons[3]).toMatchObject({ expect(targetItem?.weapons[3]).toMatchObject({
skills: [ skills: [
{ {
id: '1221' id: '1221'
@@ -1,8 +1,9 @@
import { RootWeaponData, WeaponData } from '../../data/types'
import { getRawEquipmentSkillDataMap, RawEquipmentSkillData } from '../raw/equipmentSkillData' import { getRawEquipmentSkillDataMap, RawEquipmentSkillData } from '../raw/equipmentSkillData'
import { getRawWeaponDataMap } from '../raw/weaponData' import { getRawWeaponDataMap } from '../raw/weaponData'
import { convertTagType, convertWeaponType, getText } from './utils' import { convertTagType, convertWeaponType, getText } from './utils'
export function compileWeaponData() { export function compileWeaponData(): RootWeaponData[] {
const rawWeaponDataMap = getRawWeaponDataMap() const rawWeaponDataMap = getRawWeaponDataMap()
const rawEquipmentSkillDataMap = getRawEquipmentSkillDataMap() const rawEquipmentSkillDataMap = getRawEquipmentSkillDataMap()
@@ -20,7 +21,13 @@ export function compileWeaponData() {
const rawSkill = rawEquipmentSkillDataMap[skillId] const rawSkill = rawEquipmentSkillDataMap[skillId]
skills.push({ skills.push({
id: skillId, id: skillId,
...convertWeaponSkill(rawSkill) ...convertWeaponSkill(rawSkill),
param1: rawData.Prop1Param1,
param1Add: rawData.Prop1Param1Add,
param2: rawData.Prop1Param2,
param2Add: rawData.Prop1Param2Add,
param3: rawData.Prop1Param3,
param3Add: rawData.Prop1Param3Add
}) })
} }
if (rawData.Prop2ID !== 0) { if (rawData.Prop2ID !== 0) {
@@ -28,7 +35,13 @@ export function compileWeaponData() {
const rawSkill = rawEquipmentSkillDataMap[skillId] const rawSkill = rawEquipmentSkillDataMap[skillId]
skills.push({ skills.push({
id: skillId, id: skillId,
...convertWeaponSkill(rawSkill) ...convertWeaponSkill(rawSkill),
param1: rawData.Prop2Param1,
param1Add: rawData.Prop2Param1Add,
param2: rawData.Prop2Param2,
param2Add: rawData.Prop2Param2Add,
param3: rawData.Prop2Param3,
param3Add: rawData.Prop2Param3Add
}) })
} }
if (rawData.Prop3ID !== 0) { if (rawData.Prop3ID !== 0) {
@@ -36,16 +49,22 @@ export function compileWeaponData() {
const rawSkill = rawEquipmentSkillDataMap[skillId] const rawSkill = rawEquipmentSkillDataMap[skillId]
skills.push({ skills.push({
id: skillId, id: skillId,
...convertWeaponSkill(rawSkill) ...convertWeaponSkill(rawSkill),
param1: rawData.Prop3Param1,
param1Add: rawData.Prop3Param1Add,
param2: rawData.Prop3Param2,
param2Add: rawData.Prop3Param2Add,
param3: rawData.Prop3Param3,
param3Add: rawData.Prop3Param3Add
}) })
} }
const icon = rawData.IconPath.split('/').pop() const icon = rawData.IconPath.split('/').pop()!
weaponList.push({ weaponList.push({
id, id,
rarity: rawData.Rarity, rarity: rawData.Rarity,
maxLv: rawData.MaxLv, maxLv: rawData.MaxLv,
type: convertWeaponType(rawData.BaseType), type: convertWeaponType(rawData.BaseType),
title: getText(rawData.DisplayTitle), name: getText(rawData.DisplayTitle),
description: getText(rawData.DisplayDescription), description: getText(rawData.DisplayDescription),
icon, icon,
hpBase: rawData.HPBase, hpBase: rawData.HPBase,
@@ -71,14 +90,14 @@ export function compileWeaponData() {
powerType: rawData.PowerType powerType: rawData.PowerType
}) })
return map return map
}, new Map()) }, new Map<string, WeaponData[]>())
const weaponIdList = [...rawWeaponMainIdWeaponDataMap.keys()] const weaponIdList = [...rawWeaponMainIdWeaponDataMap.keys()]
return weaponIdList.map(weaponId => { return weaponIdList.map(weaponId => {
return { return {
id: weaponId, id: weaponId,
weapons: rawWeaponMainIdWeaponDataMap.get(weaponId) weapons: rawWeaponMainIdWeaponDataMap.get(weaponId) || []
} }
}) })
+1 -1
View File
@@ -9,7 +9,7 @@ export type RawWeaponDataMap = {
} }
export interface RawWeaponData { export interface RawWeaponData {
Rarity: number Rarity: 1 | 2 | 3 | 4 | 5 | 6
MaxRarity: number MaxRarity: number
SubRarity: number SubRarity: number
SubMaxRarity: number SubMaxRarity: number
+1
View File
@@ -3,6 +3,7 @@ const HomePage = () => {
<div> <div>
<h1>V2 Pre</h1> <h1>V2 Pre</h1>
<a href="/v2-pre/battlesuits">Battlesuits</a> <a href="/v2-pre/battlesuits">Battlesuits</a>
<a href="/v2-pre/weapons">Weapons</a>
</div> </div>
) )
} }
+115
View File
@@ -0,0 +1,115 @@
import { NextPageContext } from 'next'
import { Box, Card, Flex, Heading } from 'theme-ui'
import FormattedText from '../../../components/v2-pre/FormattedText'
import { formatSubSkillInfo } from '../../../lib/v2-pre/data/formatText'
import { loadWeaponCatalog, loadWeaponData } from '../../../lib/v2-pre/server/loadData'
import { RootWeaponData, SkillTagItem } from '../../../lib/v2-pre/data/types'
import { Fragment } from 'react'
import TagIcon from '../../../components/v2-pre/TagIcon'
import { getWeaponTypeLabel } from '../../../lib/v2-pre/data/text'
import WeaponTypeIcon from '../../../components/v2-pre/WeaponTypeIcon'
import WeaponIcon from '../../../components/v2-pre/WeaponIcon'
interface WeaponShowPageProps {
rootWeapon: RootWeaponData
}
const WeaponShowPage = ({ rootWeapon }: WeaponShowPageProps) => {
const weapon = rootWeapon.weapons[rootWeapon.weapons.length - 1]
return (
<Box>
<Heading as="h1">{weapon.name}</Heading>
<Box mb={3}>
<WeaponIcon key={weapon.id} icon={weapon.icon} rarity={weapon.rarity} />
</Box>
<Card mb={3}>
<Box sx={{ p: 1, borderBottom: 'default' }}>{weapon.description}</Box>
<Flex sx={{ alignItems: 'center', p: 1, borderBottom: 'default' }}>
<WeaponTypeIcon type={weapon.type} />
<Box ml={1}>{getWeaponTypeLabel(weapon.type)}</Box>
</Flex>
<Box sx={{ p: 1 }}>
ATK : {Math.floor(weapon.attackBase + weapon.attackAdd * (weapon.maxLv - 1))} / CRT :{' '}
{Math.floor(weapon.criticalBase + weapon.criticalAdd * (weapon.maxLv - 1))} (at Max Lv {weapon.maxLv})
</Box>
</Card>
<Heading as="h2">Skills</Heading>
<Card>
{weapon.skills.map(skill => {
return (
<Fragment key={skill.id}>
<Box sx={{ borderBottom: 'default' }}>
<Heading
as="h3"
sx={{
p: 1,
m: 1
}}
>
{skill.name}
</Heading>
</Box>
<Box
sx={{
p: 1,
borderBottom: 'default',
'&:last-child': {
borderBottom: 'none'
}
}}
>
<FormattedText>
{formatSubSkillInfo({
info: skill.info,
maxLv: weapon.maxLv,
paramBase1: skill.param1,
paramBase2: skill.param2,
paramBase3: skill.param3,
paramAdd1: skill.param1Add,
paramAdd2: skill.param2Add,
paramAdd3: skill.param3Add
})}
</FormattedText>
</Box>
</Fragment>
)
})}
</Card>
{/* <pre>{JSON.stringify(weapon, null, 2)}</pre> */}
</Box>
)
}
export default WeaponShowPage
export async function getStaticProps({ locale, params }: NextPageContext & { params: { weaponId: string } }) {
const rootWeapon = loadWeaponData(params.weaponId)
return {
props: { rootWeapon }
}
}
export async function getStaticPaths() {
const weaponCatalog = loadWeaponCatalog()
return {
paths: weaponCatalog.map(catalogItem => {
return {
params: { weaponId: catalogItem.id }
}
}),
fallback: false
}
}
interface SkillTagBoxProps {
tag: SkillTagItem
}
const SkillTagItem = ({ tag }: SkillTagBoxProps) => {
return <TagIcon type={tag.type} strength={tag.strength} comment={tag.comment} size="sm" />
}
+127
View File
@@ -0,0 +1,127 @@
/** @jsxImportSource theme-ui */
import { Box, Card } from '@theme-ui/components'
import { NextPageContext } from 'next'
import { Flex, Link } from 'theme-ui'
import { loadWeaponCatalog } from '../../../lib/v2-pre/server/loadData'
import { WeaponCatalogItem } from '../../../lib/v2-pre/data/types'
import WeaponIcon from '../../../components/v2-pre/WeaponIcon'
interface BattlesuitListPageProps {
weaponCatalog: WeaponCatalogItem[]
}
const BattlesuitListPage = ({ weaponCatalog }: BattlesuitListPageProps) => {
return (
<Box>
<h1>Weapons</h1>
<Flex sx={{ flexWrap: 'wrap' }}>
{weaponCatalog
.filter(filterWeapons)
.sort(sortWeapons)
.map(weapon => {
return (
<Box key={weapon.id} m={2}>
<Link href={`/v2-pre/weapons/${weapon.id}`}>
<Card p={1}>
<Flex sx={{ justifyContent: 'center' }}>
<WeaponIcon icon={weapon.icon} rarity={weapon.maxRarity} />
</Flex>
<Box
sx={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap',
px: 1,
width: 112,
textAlign: 'center'
}}
>
{weapon.name}
</Box>
{/* {weapon.id} */}
</Card>
</Link>
</Box>
)
})}
</Flex>
</Box>
)
}
export default BattlesuitListPage
export async function getStaticProps({ locale }: NextPageContext) {
const weaponCatalog = loadWeaponCatalog()
return {
props: { weaponCatalog }
}
}
function filterWeapons(weapon: WeaponCatalogItem) {
// Valid weapons
// 24XXX EX Weapons
// 21XXX Sprit Weapon
// 19XXX Alloy Weapons
// 10XXX Regular Weapons
// Event Weapon?
if (weapon.id.startsWith('18') && weapon.id.length === 5) {
return false
}
// Test Data?
if (weapon.id.startsWith('1023') && weapon.id.length === 6) {
return false
}
// Unreleased(Number looks good but lacking info)
switch (weapon.id) {
case '24000': // 2nd relic alpha
case '24040': // Removed 7 Thunders
case '24034': // PE Temp Lance
case '24024': // keqing ex
case '20765': // ?
case '10243': // No Name
case '10219': // ?
case '10179': // ?
return false
}
// Divine Keys
switch (weapon.id) {
case '20000': // Taixuan Sword
case '10248': // Abyss Flower
case '10267': // Eden's star anti entropy
case '10263': // 7 Thunders
case '10247': // Abyss
case '10235': // Fenghuang pistols
case '10234': // Fenghuang fists
case '10223': // Eden twin stars
case '10212': // Pledge of Sakura
case '10211': // Pledge of Judah
case '10209': // Might of an utu
case '10199': // Cleaver of Shamash
case '10163': // Shamash pistols
// The below don't have duplicated data
// case '10180': // Eden's star
// case '10169': // Taxiuan fists
// case '10158': // Jizo Mitama
return false
}
return true
}
function sortWeapons(a: WeaponCatalogItem, b: WeaponCatalogItem) {
let aId = parseInt(a.id)
const aTypeOrder = aId > 21000 && aId < 22000 ? 2 : aId > 19000 && aId < 20000 ? 1 : 0
let bId = parseInt(b.id)
const bTypeOrder = bId > 21000 && bId < 22000 ? 2 : bId > 19000 && bId < 20000 ? 1 : 0
if (aTypeOrder !== bTypeOrder) {
return aTypeOrder - bTypeOrder
}
return bId - aId
}
+1
View File
@@ -52,6 +52,7 @@ function writeWeaponData() {
return { return {
id: weapon.id, id: weapon.id,
name: maxedWeapon.name, name: maxedWeapon.name,
icon: maxedWeapon.icon,
type: maxedWeapon.type, type: maxedWeapon.type,
maxRarity: maxedWeapon.rarity maxRarity: maxedWeapon.rarity
} }