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