feat: implement combat simulation modules and localization support for game modes
Gitea Auto Deploy / Deploy-Container (push) Successful in 44s
Gitea Auto Deploy / Deploy-Container (push) Successful in 44s
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Turbulenz-Buff verwenden?",
|
||||
"firstHalfEnemies": "Gegner erste Hälfte",
|
||||
"secondHalfEnemies": "Gegner zweite Hälfte",
|
||||
"firstNodeEnemies": "Gegner Knoten 1",
|
||||
"secondNodeEnemies": "Gegner Knoten 2",
|
||||
"thirdNodeEnemies": "Gegner Knoten 3",
|
||||
"firstNode": "Knoten 1",
|
||||
"secondNode": "Knoten 2",
|
||||
"thirdNode": "Knoten 3",
|
||||
"listEnemies": "Gegnerliste",
|
||||
"turbulenceBuff": "Turbulenz-Buff",
|
||||
"noEventSelected": "Kein Ereignis ausgewählt",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Use turbulence buff?",
|
||||
"firstHalfEnemies": "First half enemies",
|
||||
"secondHalfEnemies": "Second half enemies",
|
||||
"firstNodeEnemies": "First node enemies",
|
||||
"secondNodeEnemies": "Second node enemies",
|
||||
"thirdNodeEnemies": "Third node enemies",
|
||||
"firstNode": "First Node",
|
||||
"secondNode": "Second Node",
|
||||
"thirdNode": "Third Node",
|
||||
"listEnemies": "List enemies",
|
||||
"turbulenceBuff": "Turbulence Buff",
|
||||
"noEventSelected": "No event selected",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "¿Usar buff de turbulencia?",
|
||||
"firstHalfEnemies": "Enemigos primera mitad",
|
||||
"secondHalfEnemies": "Enemigos segunda mitad",
|
||||
"firstNodeEnemies": "Enemigos del nodo 1",
|
||||
"secondNodeEnemies": "Enemigos del nodo 2",
|
||||
"thirdNodeEnemies": "Enemigos del nodo 3",
|
||||
"firstNode": "Nodo 1",
|
||||
"secondNode": "Nodo 2",
|
||||
"thirdNode": "Nodo 3",
|
||||
"listEnemies": "Lista de enemigos",
|
||||
"turbulenceBuff": "Buff de Turbulencia",
|
||||
"noEventSelected": "Ningún evento seleccionado",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Utiliser le buff de turbulence ?",
|
||||
"firstHalfEnemies": "Ennemis première moitié",
|
||||
"secondHalfEnemies": "Ennemis deuxième moitié",
|
||||
"firstNodeEnemies": "Ennemis du nœud 1",
|
||||
"secondNodeEnemies": "Ennemis du nœud 2",
|
||||
"thirdNodeEnemies": "Ennemis du nœud 3",
|
||||
"firstNode": "Nœud 1",
|
||||
"secondNode": "Nœud 2",
|
||||
"thirdNode": "Nœud 3",
|
||||
"listEnemies": "Liste des ennemis",
|
||||
"turbulenceBuff": "Buff de Turbulence",
|
||||
"noEventSelected": "Aucun événement sélectionné",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Gunakan buff turbulence?",
|
||||
"firstHalfEnemies": "Musuh paruh pertama",
|
||||
"secondHalfEnemies": "Musuh paruh kedua",
|
||||
"firstNodeEnemies": "Musuh Node 1",
|
||||
"secondNodeEnemies": "Musuh Node 2",
|
||||
"thirdNodeEnemies": "Musuh Node 3",
|
||||
"firstNode": "Node 1",
|
||||
"secondNode": "Node 2",
|
||||
"thirdNode": "Node 3",
|
||||
"listEnemies": "Daftar musuh",
|
||||
"turbulenceBuff": "Turbulence Buff",
|
||||
"noEventSelected": "Tidak ada event dipilih",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "乱気流バフを使用しますか?",
|
||||
"firstHalfEnemies": "前半の敵",
|
||||
"secondHalfEnemies": "後半の敵",
|
||||
"firstNodeEnemies": "ノード 1 の敵",
|
||||
"secondNodeEnemies": "ノード 2 の敵",
|
||||
"thirdNodeEnemies": "ノード 3 の敵",
|
||||
"firstNode": "ノード 1",
|
||||
"secondNode": "ノード 2",
|
||||
"thirdNode": "ノード 3",
|
||||
"turbulenceBuff": "乱気流バフ",
|
||||
"noEventSelected": "イベントが選択されていません",
|
||||
"noTurbulenceBuff": "乱気流バフがありません",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "난류 버프 사용?",
|
||||
"firstHalfEnemies": "전반 적",
|
||||
"secondHalfEnemies": "후반 적",
|
||||
"firstNodeEnemies": "노드 1 적",
|
||||
"secondNodeEnemies": "노드 2 적",
|
||||
"thirdNodeEnemies": "노드 3 적",
|
||||
"firstNode": "노드 1",
|
||||
"secondNode": "노드 2",
|
||||
"thirdNode": "노드 3",
|
||||
"turbulenceBuff": "난류 버프",
|
||||
"noEventSelected": "이벤트가 선택되지 않음",
|
||||
"noTurbulenceBuff": "난류 버프가 없음",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Usar buff de turbulência?",
|
||||
"firstHalfEnemies": "Inimigos da primeira metade",
|
||||
"secondHalfEnemies": "Inimigos da segunda metade",
|
||||
"firstNodeEnemies": "Inimigos do nodo 1",
|
||||
"secondNodeEnemies": "Inimigos do nodo 2",
|
||||
"thirdNodeEnemies": "Inimigos do nodo 3",
|
||||
"firstNode": "Nodo 1",
|
||||
"secondNode": "Nodo 2",
|
||||
"thirdNode": "Nodo 3",
|
||||
"listEnemies": "Lista de inimigos",
|
||||
"turbulenceBuff": "Buff de Turbulência",
|
||||
"noEventSelected": "Nenhum evento selecionado",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Использовать бафф турбулентности?",
|
||||
"firstHalfEnemies": "Враги первой половины",
|
||||
"secondHalfEnemies": "Враги второй половины",
|
||||
"firstNodeEnemies": "Враги узла 1",
|
||||
"secondNodeEnemies": "Враги узла 2",
|
||||
"thirdNodeEnemies": "Враги узла 3",
|
||||
"firstNode": "Узел 1",
|
||||
"secondNode": "Узел 2",
|
||||
"thirdNode": "Узел 3",
|
||||
"listEnemies": "Список врагов",
|
||||
"turbulenceBuff": "Бафф турбулентности",
|
||||
"noEventSelected": "Событие не выбрано",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "ใช้บัฟบรรยากาศหรือไม่?",
|
||||
"firstHalfEnemies": "ศัตรูครึ่งแรก",
|
||||
"secondHalfEnemies": "ศัตรูครึ่งหลัง",
|
||||
"firstNodeEnemies": "ศัตรูโหนด 1",
|
||||
"secondNodeEnemies": "ศัตรูโหนด 2",
|
||||
"thirdNodeEnemies": "ศัตรูโหนด 3",
|
||||
"firstNode": "โหนด 1",
|
||||
"secondNode": "โหนด 2",
|
||||
"thirdNode": "โหนด 3",
|
||||
"listEnemies": "รายการศัตรู",
|
||||
"turbulenceBuff": "บัฟบรรยากาศ",
|
||||
"noEventSelected": "ไม่ได้เลือกอีเวนต์",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "Dùng buff hỗn loạn?",
|
||||
"firstHalfEnemies": "Địch nửa đầu",
|
||||
"secondHalfEnemies": "Địch nửa sau",
|
||||
"firstNodeEnemies": "Địch Node 1",
|
||||
"secondNodeEnemies": "Địch Node 2",
|
||||
"thirdNodeEnemies": "Địch Node 3",
|
||||
"firstNode": "Node 1",
|
||||
"secondNode": "Node 2",
|
||||
"thirdNode": "Node 3",
|
||||
"turbulenceBuff": "Buff hỗn loạn",
|
||||
"noEventSelected": "Không có sự kiện",
|
||||
"noTurbulenceBuff": "Không có buff hỗn loạn",
|
||||
|
||||
@@ -189,6 +189,12 @@
|
||||
"useTurbulenceBuff": "使用记忆紊流?",
|
||||
"firstHalfEnemies": "上半场敌人",
|
||||
"secondHalfEnemies": "下半场敌人",
|
||||
"firstNodeEnemies": "节点 1 敌人",
|
||||
"secondNodeEnemies": "节点 2 敌人",
|
||||
"thirdNodeEnemies": "节点 3 敌人",
|
||||
"firstNode": "节点 1",
|
||||
"secondNode": "节点 2",
|
||||
"thirdNode": "节点 3",
|
||||
"turbulenceBuff": "增益效果",
|
||||
"noEventSelected": "未选择事件",
|
||||
"noTurbulenceBuff": "未选择增益效果",
|
||||
|
||||
@@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import useUserDataStore from "@/stores/userDataStore";
|
||||
import Image from "next/image";
|
||||
import { MonsterStore } from "@/types";
|
||||
import { ASEvent, MonsterStore } from "@/types";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useDetailDataStore from "@/stores/detailDataStore";
|
||||
|
||||
@@ -16,7 +16,6 @@ export default function AsBar() {
|
||||
setAsConfig
|
||||
} = useUserDataStore()
|
||||
const { mapMonster, mapAS, damageType, hardLevelConfig, eliteConfig } = useDetailDataStore()
|
||||
|
||||
const transI18n = useTranslations("DataPage")
|
||||
|
||||
const challengeSelected = useMemo(() => {
|
||||
@@ -27,20 +26,52 @@ export default function AsBar() {
|
||||
return mapAS[as_config.event_id.toString()]
|
||||
}, [as_config, mapAS])
|
||||
|
||||
|
||||
const floorSideList = useMemo(() => {
|
||||
if (!eventSelected) return [];
|
||||
|
||||
const floorList = [
|
||||
{
|
||||
id: "firstNode",
|
||||
name: transI18n("firstNode"),
|
||||
wave: transI18n("firstNodeEnemies")
|
||||
},
|
||||
{
|
||||
id: "secondNode",
|
||||
name: transI18n("secondNode"),
|
||||
wave: transI18n("secondNodeEnemies")
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === as_config.challenge_id) {
|
||||
floorList.push({
|
||||
id: "thirdNode",
|
||||
name: transI18n("thirdNode"),
|
||||
wave: transI18n("thirdNodeEnemies")
|
||||
})
|
||||
}
|
||||
return floorList
|
||||
}, [as_config.challenge_id, eventSelected, transI18n])
|
||||
|
||||
const buffList = useMemo(() => {
|
||||
if (!eventSelected) return [];
|
||||
|
||||
if (as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower") {
|
||||
if (as_config.floor_side === "firstNode") {
|
||||
return eventSelected?.BuffList1 ?? [];
|
||||
}
|
||||
|
||||
if (as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper") {
|
||||
if (as_config.floor_side === "secondNode") {
|
||||
return eventSelected?.BuffList2 ?? [];
|
||||
}
|
||||
|
||||
if (as_config.floor_side === "thirdNode" && eventSelected?.BuffList3) {
|
||||
return eventSelected?.BuffList3 ?? [];
|
||||
}
|
||||
|
||||
return [];
|
||||
}, [as_config.floor_side, eventSelected]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!challengeSelected || as_config.event_id === 0 || as_config.challenge_id === 0) return
|
||||
const newBattleConfig = structuredClone(as_config)
|
||||
@@ -65,67 +96,36 @@ export default function AsBar() {
|
||||
|
||||
newBattleConfig.monsters = []
|
||||
newBattleConfig.stage_id = 0
|
||||
if ((as_config.floor_side === "Upper" || as_config.floor_side === "Upper -> Lower")
|
||||
&& challengeSelected.EventList1.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
|
||||
let targetEventList: ASEvent[] = []
|
||||
if (as_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
|
||||
targetEventList = challengeSelected.EventList1
|
||||
} else if (as_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
|
||||
targetEventList = challengeSelected.EventList2
|
||||
} else if (as_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
|
||||
targetEventList = eventSelected.Tierce.EventList
|
||||
}
|
||||
|
||||
if (targetEventList.length > 0) {
|
||||
newBattleConfig.stage_id = targetEventList[0].ID
|
||||
for (const wave of targetEventList[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if ((as_config.floor_side === "Lower" || as_config.floor_side === "Lower -> Upper")
|
||||
&& challengeSelected.EventList2.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if (as_config.floor_side === "Lower -> Upper"
|
||||
&& challengeSelected.EventList1.length > 0) {
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
} else if (as_config.floor_side === "Upper -> Lower"
|
||||
&& challengeSelected.EventList2.length > 0) {
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
level: targetEventList[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
|
||||
setAsConfig(newBattleConfig)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
challengeSelected,
|
||||
eventSelected,
|
||||
mapAS,
|
||||
as_config.event_id,
|
||||
as_config.challenge_id,
|
||||
@@ -186,10 +186,9 @@ export default function AsBar() {
|
||||
onChange={(e) => setAsConfig({ ...as_config, floor_side: e.target.value })}
|
||||
>
|
||||
<option value={0} disabled={true}>{transI18n("selectSide")}</option>
|
||||
<option value="Upper">{transI18n("upper")}</option>
|
||||
<option value="Lower">{transI18n("lower")}</option>
|
||||
<option value="Upper -> Lower">{transI18n("upperToLower")}</option>
|
||||
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
|
||||
{floorSideList.map((side) => {
|
||||
return <option key={side.id} value={side.id}>{side.name}</option>
|
||||
})}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -233,21 +232,33 @@ export default function AsBar() {
|
||||
|
||||
{/* Enemy Waves */}
|
||||
{(as_config?.challenge_id ?? 0) !== 0 && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{/* First Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{floorSideList.map((side, i) => {
|
||||
const eventList = side.id === "firstNode"
|
||||
? challengeSelected?.EventList1
|
||||
: side.id === "secondNode"
|
||||
? challengeSelected?.EventList2
|
||||
: side.id === "thirdNode"
|
||||
? eventSelected?.Tierce?.EventList
|
||||
: [];
|
||||
|
||||
{challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => (
|
||||
if (!eventList || eventList.length === 0) return null;
|
||||
const targetEvent = eventList[0];
|
||||
|
||||
return (
|
||||
<div key={i} className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{side.wave}</h2>
|
||||
|
||||
{targetEvent?.MonsterList?.map((wave, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{Object.values(wave).map((waveValue, enemyIndex) => {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[waveValue.toString()],
|
||||
challengeSelected?.EventList1?.[0]?.EliteGroup,
|
||||
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList1?.[0]?.Level,
|
||||
targetEvent?.EliteGroup,
|
||||
targetEvent?.HardLevelGroup,
|
||||
targetEvent?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
@@ -257,7 +268,7 @@ export default function AsBar() {
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList1[0].Level}
|
||||
Lv. {targetEvent.Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
@@ -321,94 +332,7 @@ export default function AsBar() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Second Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
|
||||
|
||||
{challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold mb-t">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{Object.values(wave).map((waveValue, enemyIndex) => {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[waveValue.toString()],
|
||||
challengeSelected?.EventList2?.[0]?.EliteGroup,
|
||||
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList2?.[0]?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={enemyIndex}
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList2[0].Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
|
||||
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
|
||||
<Image
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
|
||||
alt="Enemy Icon"
|
||||
width={150}
|
||||
height={150}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col px-1 pb-2 pt-2">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-error">HP</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-info">Speed</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
|
||||
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
|
||||
Weakness
|
||||
</span>
|
||||
<div className="flex items-center justify-center gap-1.5 flex-wrap">
|
||||
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
|
||||
<Image
|
||||
key={iconIndex}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
|
||||
alt={icon}
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import useLocaleStore from "@/stores/localeStore";
|
||||
import useUserDataStore from "@/stores/userDataStore";
|
||||
import Image from "next/image";
|
||||
import { useTranslations } from "next-intl";
|
||||
import { MonsterStore } from "@/types";
|
||||
import { MoCEvent, MonsterStore } from "@/types";
|
||||
import useDetailDataStore from "@/stores/detailDataStore";
|
||||
|
||||
export default function MocBar() {
|
||||
@@ -28,6 +28,33 @@ export default function MocBar() {
|
||||
return mapMoc[moc_config.event_id.toString()]
|
||||
}, [moc_config, mapMoc])
|
||||
|
||||
const floorSideList = useMemo(() => {
|
||||
if (!eventSelected) return [];
|
||||
|
||||
const floorList = [
|
||||
{
|
||||
id: "firstNode",
|
||||
name: transI18n("firstNode"),
|
||||
wave: transI18n("firstNodeEnemies")
|
||||
},
|
||||
{
|
||||
id: "secondNode",
|
||||
name: transI18n("secondNode"),
|
||||
wave: transI18n("secondNodeEnemies")
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === moc_config.challenge_id) {
|
||||
floorList.push({
|
||||
id: "thirdNode",
|
||||
name: transI18n("thirdNode"),
|
||||
wave: transI18n("thirdNodeEnemies")
|
||||
})
|
||||
}
|
||||
return floorList
|
||||
}, [moc_config.challenge_id, eventSelected, transI18n])
|
||||
|
||||
useEffect(() => {
|
||||
if (!challengeSelected || moc_config.event_id === 0 || moc_config.challenge_id === 0) return
|
||||
|
||||
@@ -47,62 +74,36 @@ export default function MocBar() {
|
||||
}
|
||||
newBattleConfig.monsters = []
|
||||
newBattleConfig.stage_id = 0
|
||||
if ((moc_config.floor_side === "Upper" || moc_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
|
||||
let targetEventList: MoCEvent[] = []
|
||||
if (moc_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
|
||||
targetEventList = challengeSelected.EventList1
|
||||
} else if (moc_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
|
||||
targetEventList = challengeSelected.EventList2
|
||||
} else if (moc_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
|
||||
targetEventList = eventSelected.Tierce.EventList
|
||||
}
|
||||
|
||||
if (targetEventList.length > 0) {
|
||||
newBattleConfig.stage_id = targetEventList[0].ID
|
||||
for (const wave of targetEventList[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if ((moc_config.floor_side === "Lower" || moc_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if (moc_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) {
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
} else if (moc_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) {
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
level: targetEventList[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
|
||||
setMocConfig(newBattleConfig)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
challengeSelected,
|
||||
eventSelected,
|
||||
moc_config.event_id,
|
||||
moc_config.challenge_id,
|
||||
moc_config.floor_side,
|
||||
@@ -168,10 +169,9 @@ export default function MocBar() {
|
||||
onChange={(e) => setMocConfig({ ...moc_config, floor_side: e.target.value })}
|
||||
>
|
||||
<option value={0} disabled={true}>{transI18n("selectSide")}</option>
|
||||
<option value="Upper">{transI18n("upper")}</option>
|
||||
<option value="Lower">{transI18n("lower")}</option>
|
||||
<option value="Upper -> Lower">{transI18n("upperToLower")}</option>
|
||||
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
|
||||
{floorSideList.map((side) => (
|
||||
<option key={side.id} value={side.id}>{side.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -232,21 +232,33 @@ export default function MocBar() {
|
||||
|
||||
{/* Enemy Waves */}
|
||||
{(moc_config?.challenge_id ?? 0) !== 0 && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{/* First Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("firstHalfEnemies")}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{floorSideList.map((side, i) => {
|
||||
const eventList = side.id === "firstNode"
|
||||
? challengeSelected?.EventList1
|
||||
: side.id === "secondNode"
|
||||
? challengeSelected?.EventList2
|
||||
: side.id === "thirdNode"
|
||||
? eventSelected?.Tierce?.EventList
|
||||
: [];
|
||||
|
||||
{challengeSelected && challengeSelected?.EventList1?.length > 0 && challengeSelected?.EventList1?.[0]?.MonsterList?.map((wave, waveIndex) => (
|
||||
if (!eventList || eventList.length === 0) return null;
|
||||
const targetEvent = eventList[0];
|
||||
|
||||
return (
|
||||
<div key={i} className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{side.wave}</h2>
|
||||
|
||||
{targetEvent?.MonsterList?.map((wave, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{Object.values(wave).map((waveValue, enemyIndex) => {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[waveValue.toString()],
|
||||
challengeSelected?.EventList1?.[0]?.EliteGroup,
|
||||
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList1?.[0]?.Level,
|
||||
targetEvent?.EliteGroup,
|
||||
targetEvent?.HardLevelGroup,
|
||||
targetEvent?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
@@ -256,7 +268,7 @@ export default function MocBar() {
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList1[0].Level}
|
||||
Lv. {targetEvent.Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
@@ -320,95 +332,9 @@ export default function MocBar() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Second Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
|
||||
|
||||
{challengeSelected && challengeSelected?.EventList2?.length > 0 && challengeSelected?.EventList2?.[0]?.MonsterList?.map((wave, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{Object.values(wave).map((waveValue, enemyIndex) => {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[waveValue.toString()],
|
||||
challengeSelected?.EventList2?.[0]?.EliteGroup,
|
||||
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList2?.[0]?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={enemyIndex}
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList2[0].Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
{mapMonster?.[waveValue.toString()]?.Image?.IconPath && (
|
||||
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
|
||||
<Image
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${mapMonster?.[waveValue.toString()]?.Image?.IconPath}`}
|
||||
alt="Enemy Icon"
|
||||
width={150}
|
||||
height={150}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col px-1 pb-2 pt-2">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-error">HP</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-info">Speed</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
|
||||
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
|
||||
Weakness
|
||||
</span>
|
||||
<div className="flex items-center justify-center gap-1.5 flex-wrap">
|
||||
{mapMonster?.[waveValue.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
|
||||
<Image
|
||||
key={iconIndex}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
|
||||
alt={icon}
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@ import { calcMonsterStats, getLocaleName, replaceByParam } from "@/helper";
|
||||
import useLocaleStore from "@/stores/localeStore";
|
||||
import useUserDataStore from "@/stores/userDataStore";
|
||||
import Image from "next/image";
|
||||
import { MonsterStore } from "@/types";
|
||||
import { MonsterStore, PFEvent } from "@/types";
|
||||
import { useTranslations } from "next-intl";
|
||||
import useDetailDataStore from "@/stores/detailDataStore";
|
||||
|
||||
@@ -26,6 +26,33 @@ export default function PfBar() {
|
||||
return mapPF[pf_config.event_id.toString()]
|
||||
}, [pf_config, mapPF])
|
||||
|
||||
const floorSideList = useMemo(() => {
|
||||
if (!eventSelected) return [];
|
||||
|
||||
const floorList = [
|
||||
{
|
||||
id: "firstNode",
|
||||
name: transI18n("firstNode"),
|
||||
wave: transI18n("firstNodeEnemies")
|
||||
},
|
||||
{
|
||||
id: "secondNode",
|
||||
name: transI18n("secondNode"),
|
||||
wave: transI18n("secondNodeEnemies")
|
||||
},
|
||||
|
||||
]
|
||||
|
||||
if (eventSelected?.Tierce && eventSelected.Tierce.PreChallenge === pf_config.challenge_id) {
|
||||
floorList.push({
|
||||
id: "thirdNode",
|
||||
name: transI18n("thirdNode"),
|
||||
wave: transI18n("thirdNodeEnemies")
|
||||
})
|
||||
}
|
||||
return floorList
|
||||
}, [pf_config.challenge_id, eventSelected, transI18n])
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
if (!challengeSelected || pf_config.event_id === 0 || pf_config.challenge_id === 0) {
|
||||
@@ -50,63 +77,36 @@ export default function PfBar() {
|
||||
}
|
||||
newBattleConfig.monsters = []
|
||||
newBattleConfig.stage_id = 0
|
||||
if ((pf_config.floor_side === "Upper" || pf_config.floor_side === "Upper -> Lower") && challengeSelected.EventList1.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList1[0].ID
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
|
||||
let targetEventList: PFEvent[] = []
|
||||
if (pf_config.floor_side === "firstNode" && challengeSelected.EventList1.length > 0) {
|
||||
targetEventList = challengeSelected.EventList1
|
||||
} else if (pf_config.floor_side === "secondNode" && challengeSelected.EventList2.length > 0) {
|
||||
targetEventList = challengeSelected.EventList2
|
||||
} else if (pf_config.floor_side === "thirdNode" && eventSelected?.Tierce && eventSelected.Tierce.EventList.length > 0) {
|
||||
targetEventList = eventSelected.Tierce.EventList
|
||||
}
|
||||
|
||||
if (targetEventList.length > 0) {
|
||||
newBattleConfig.stage_id = targetEventList[0].ID
|
||||
for (const wave of targetEventList[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if ((pf_config.floor_side === "Lower" || pf_config.floor_side === "Lower -> Upper") && challengeSelected.EventList2.length > 0) {
|
||||
newBattleConfig.stage_id = challengeSelected.EventList2[0].ID
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
if (pf_config.floor_side === "Lower -> Upper" && challengeSelected.EventList1.length > 0) {
|
||||
for (const wave of challengeSelected.EventList1[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList1[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
} else if (pf_config.floor_side === "Upper -> Lower" && challengeSelected.EventList2.length > 0) {
|
||||
for (const wave of challengeSelected.EventList2[0].MonsterList) {
|
||||
const newWave: MonsterStore[] = []
|
||||
for (const value of Object.values(wave)) {
|
||||
newWave.push({
|
||||
monster_id: value,
|
||||
level: challengeSelected.EventList2[0].Level,
|
||||
monster_id: value as number,
|
||||
level: targetEventList[0].Level,
|
||||
amount: 1,
|
||||
})
|
||||
}
|
||||
newBattleConfig.monsters.push(newWave)
|
||||
}
|
||||
}
|
||||
|
||||
setPfConfig(newBattleConfig)
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||
}, [
|
||||
challengeSelected,
|
||||
eventSelected,
|
||||
pf_config.event_id,
|
||||
pf_config.challenge_id,
|
||||
pf_config.floor_side,
|
||||
@@ -167,10 +167,9 @@ export default function PfBar() {
|
||||
onChange={(e) => setPfConfig({ ...pf_config, floor_side: e.target.value })}
|
||||
>
|
||||
<option value={0} disabled={true}>{transI18n("selectSide")}</option>
|
||||
<option value="Upper">{transI18n("upper")}</option>
|
||||
<option value="Lower">{transI18n("lower")}</option>
|
||||
<option value="Upper -> Lower">{transI18n("upperToLower")}</option>
|
||||
<option value="Lower -> Upper">{transI18n("lowerToUpper")}</option>
|
||||
{floorSideList.map((side) => (
|
||||
<option key={side.id} value={side.id}>{side.name}</option>
|
||||
))}
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
@@ -232,12 +231,24 @@ export default function PfBar() {
|
||||
{/* Enemy Waves */}
|
||||
|
||||
{(pf_config?.challenge_id ?? 0) !== 0 && (
|
||||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||||
{/* First Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-2 text-info">{transI18n("firstHalfEnemies")}</h2>
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{floorSideList.map((side, i) => {
|
||||
const eventList = side.id === "firstNode"
|
||||
? challengeSelected?.EventList1
|
||||
: side.id === "secondNode"
|
||||
? challengeSelected?.EventList2
|
||||
: side.id === "thirdNode"
|
||||
? eventSelected?.Tierce?.EventList
|
||||
: [];
|
||||
|
||||
{challengeSelected && Object.values(challengeSelected.EventList1?.[0]?.Infinite || []).map((waveValue, waveIndex) => (
|
||||
if (!eventList || eventList.length === 0) return null;
|
||||
const targetEvent = eventList[0];
|
||||
|
||||
return (
|
||||
<div key={i} className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-2 text-info">{side.wave}</h2>
|
||||
|
||||
{targetEvent && Object.values(targetEvent.Infinite || []).map((waveValue, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
@@ -245,8 +256,8 @@ export default function PfBar() {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[monsterId.toString()],
|
||||
waveValue.EliteGroup,
|
||||
challengeSelected?.EventList1?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList1?.[0]?.Level,
|
||||
targetEvent?.HardLevelGroup,
|
||||
targetEvent?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
@@ -256,7 +267,7 @@ export default function PfBar() {
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList1[0].Level}
|
||||
Lv. {targetEvent.Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
@@ -320,95 +331,9 @@ export default function PfBar() {
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Second Half */}
|
||||
<div className="rounded-xl p-4 mt-2 border border-warning">
|
||||
<h2 className="text-2xl font-bold mb-6 text-info">{transI18n("secondHalfEnemies")}</h2>
|
||||
|
||||
{challengeSelected && Object.values(challengeSelected?.EventList2[0]?.Infinite || []).map((waveValue, waveIndex) => (
|
||||
<div key={waveIndex} className="mb-6">
|
||||
<h3 className="text-lg font-semibold">{transI18n("wave")} {waveIndex + 1}</h3>
|
||||
<div className="flex flex-wrap gap-2 mt-2">
|
||||
{Array.from(new Set(waveValue.MonsterList)).map((monsterId, enemyIndex) => {
|
||||
const monsterStats = calcMonsterStats(
|
||||
mapMonster?.[monsterId.toString()],
|
||||
waveValue.EliteGroup,
|
||||
challengeSelected?.EventList2?.[0]?.HardLevelGroup,
|
||||
challengeSelected?.EventList2?.[0]?.Level,
|
||||
hardLevelConfig,
|
||||
eliteConfig
|
||||
);
|
||||
return (
|
||||
<div
|
||||
key={enemyIndex}
|
||||
className="group relative flex flex-col w-40 bg-base-100 rounded-2xl border border-base-300 shadow-md"
|
||||
>
|
||||
<div className="badge badge-warning badge-sm font-bold absolute top-2 right-2 z-10 shadow-sm">
|
||||
Lv. {challengeSelected?.EventList2[0].Level}
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-20 bg-base-200 flex items-center justify-center p-4 rounded-t-2xl">
|
||||
{mapMonster?.[monsterId.toString()]?.Image?.IconPath && (
|
||||
<div className="relative w-16 h-16 rounded-full border-2 border-base-300 shadow-md overflow-hidden group-hover:scale-110 transition-transform duration-300 bg-base-100">
|
||||
<Image
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${mapMonster?.[monsterId.toString()]?.Image?.IconPath}`}
|
||||
alt="Enemy Icon"
|
||||
width={150}
|
||||
height={150}
|
||||
className="w-full h-full object-cover"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col px-1 pb-2 pt-2">
|
||||
<div className="flex flex-col space-y-1.5">
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-error">HP</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.hp.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-info">Speed</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.spd.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between items-center bg-base-200 px-2.5 py-1.5 rounded-lg">
|
||||
<span className="text-xs font-semibold text-base-content/70">Toughness</span>
|
||||
<span className="text-sm font-bold text-base-content">{monsterStats.stance.toLocaleString(undefined, { maximumFractionDigits: 0 })}</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-2 pt-2 border-t border-base-300 flex flex-col items-center">
|
||||
<span className="text-[10px] text-base-content/60 font-bold uppercase tracking-widest mb-1.5">
|
||||
Weakness
|
||||
</span>
|
||||
<div className="flex items-center justify-center gap-1.5 flex-wrap">
|
||||
{mapMonster?.[monsterId.toString()]?.StanceWeakList?.map((icon, iconIndex) => (
|
||||
<Image
|
||||
key={iconIndex}
|
||||
unoptimized
|
||||
crossOrigin="anonymous"
|
||||
src={`${process.env.CDN_URL}/${damageType[icon]?.Icon}`}
|
||||
alt={icon}
|
||||
width={40}
|
||||
height={40}
|
||||
className="h-6 w-6 object-contain rounded-full bg-base-300 border border-base-content/10 p-0.5 shadow-sm hover:scale-110 transition-transform"
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
</div>
|
||||
|
||||
@@ -9,7 +9,9 @@ export interface ASGroupDetail {
|
||||
EndTime: string;
|
||||
BuffList1: ASBuff[];
|
||||
BuffList2: ASBuff[];
|
||||
BuffList3: ASBuff[] | null;
|
||||
Level: ASLevel[];
|
||||
Tierce: ASTierceLevel | null;
|
||||
}
|
||||
|
||||
export interface ASBuff {
|
||||
@@ -21,6 +23,16 @@ export interface ASBuff {
|
||||
ExtraList?: ExtraEffect[];
|
||||
}
|
||||
|
||||
export interface ASTierceLevel {
|
||||
ID: number;
|
||||
PreChallenge: number;
|
||||
Name: Record<string, string>;
|
||||
Target: ASTarget[];
|
||||
DamageType: string[];
|
||||
TurnLimit: number;
|
||||
EventList: ASEvent[];
|
||||
}
|
||||
|
||||
export interface ASLevel {
|
||||
Floor: number;
|
||||
ID: number;
|
||||
@@ -35,6 +47,7 @@ export interface ASLevel {
|
||||
EventList2: ASEvent[];
|
||||
Monster1: ASMonster;
|
||||
Monster2: ASMonster;
|
||||
Monster3: ASMonster | null;
|
||||
}
|
||||
|
||||
export interface ASTarget {
|
||||
|
||||
@@ -7,6 +7,17 @@ export interface MOCGroupDetail {
|
||||
BeginTime: string;
|
||||
EndTime: string;
|
||||
Level: MoCLevel[];
|
||||
Tierce: MoCTierceLevel | null;
|
||||
}
|
||||
|
||||
export interface MoCTierceLevel {
|
||||
ID: number;
|
||||
PreChallenge: number;
|
||||
Name: Record<string, string>;
|
||||
Target: MoCTarget[];
|
||||
DamageType: string[];
|
||||
TurnLimit: number;
|
||||
EventList: MoCEvent[];
|
||||
}
|
||||
|
||||
export interface MoCLevel {
|
||||
|
||||
+16
-5
@@ -6,7 +6,8 @@ export interface PFGroupDetail {
|
||||
EndTime: string;
|
||||
SubOption: MazeBuff[];
|
||||
Option: MazeBuff[];
|
||||
Level: LevelData[];
|
||||
Level: PFLevel[];
|
||||
Tierce: PFTierceLevel | null;
|
||||
}
|
||||
|
||||
export interface MazeBuff {
|
||||
@@ -17,7 +18,17 @@ export interface MazeBuff {
|
||||
Desc: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface LevelData {
|
||||
export interface PFTierceLevel {
|
||||
ID: number;
|
||||
PreChallenge: number;
|
||||
Name: Record<string, string>;
|
||||
Target: StoryTarget[];
|
||||
DamageType: string[];
|
||||
TurnLimit: number;
|
||||
EventList: PFEvent[];
|
||||
}
|
||||
|
||||
export interface PFLevel {
|
||||
Floor: number;
|
||||
ID: number;
|
||||
StageNum: number;
|
||||
@@ -26,8 +37,8 @@ export interface LevelData {
|
||||
DamageType1: string[];
|
||||
DamageType2: string[];
|
||||
MazeBuff: MazeBuff[];
|
||||
EventList1: StageConfig[];
|
||||
EventList2: StageConfig[];
|
||||
EventList1: PFEvent[];
|
||||
EventList2: PFEvent[];
|
||||
TurnLimit: number;
|
||||
BattleTarget: BattleTarget[];
|
||||
ClearScore: number;
|
||||
@@ -45,7 +56,7 @@ export interface BattleTarget {
|
||||
Name: Record<string, string>;
|
||||
}
|
||||
|
||||
export interface StageConfig {
|
||||
export interface PFEvent {
|
||||
ID: number;
|
||||
Name: Record<string, string>;
|
||||
HardLevelGroup: number;
|
||||
|
||||
Reference in New Issue
Block a user