diff --git a/public/data/bosses.json b/public/data/bosses.json index 1f9deea..d2998ad 100644 --- a/public/data/bosses.json +++ b/public/data/bosses.json @@ -61,58 +61,59 @@ }, "Lotus": { "Normal": { "price": 32512500, "frequency": "weekly", "requiredLevel": 190 }, - "Hard": { "price": 74112500, "frequency": "weekly", "requiredLevel": 190 } + "Hard": { "price": 88935000, "frequency": "weekly", "requiredLevel": 190 }, + "Extreme": { "price": 279500000, "frequency": "weekly", "requiredLevel": 190 } }, "Damien": { "Normal": { "price": 33800000, "frequency": "weekly", "requiredLevel": 190 }, - "Hard": { "price": 70312500, "frequency": "weekly", "requiredLevel": 190 } + "Hard": { "price": 84375000, "frequency": "weekly", "requiredLevel": 190 } }, "Guardian Angel Slime": { - "Normal": { "price": 34322000, "frequency": "weekly", "requiredLevel": 210 }, - "Chaos": { "price": 90312500, "frequency": "weekly", "requiredLevel": 210 } + "Normal": { "price": 46334700, "frequency": "weekly", "requiredLevel": 210 }, + "Chaos": { "price": 120115625, "frequency": "weekly", "requiredLevel": 210 } }, "Lucid": { - "Easy": { "price": 35112500, "frequency": "weekly", "requiredLevel": 220 }, - "Normal": { "price": 40612500, "frequency": "weekly", "requiredLevel": 220 }, - "Hard": { "price": 80000000, "frequency": "weekly", "requiredLevel": 220 } + "Easy": { "price": 47401875, "frequency": "weekly", "requiredLevel": 220 }, + "Normal": { "price": 50765625, "frequency": "weekly", "requiredLevel": 220 }, + "Hard": { "price": 100800000, "frequency": "weekly", "requiredLevel": 220 } }, "Will": { - "Easy": { "price": 38255000, "frequency": "weekly", "requiredLevel": 235 }, - "Normal": { "price": 46512500, "frequency": "weekly", "requiredLevel": 235 }, - "Hard": { "price": 88200000, "frequency": "weekly", "requiredLevel": 235 } + "Easy": { "price": 49348950, "frequency": "weekly", "requiredLevel": 235 }, + "Normal": { "price": 55815000, "frequency": "weekly", "requiredLevel": 235 }, + "Hard": { "price": 124362000, "frequency": "weekly", "requiredLevel": 235 } }, "Gloom": { - "Normal": { "price": 49612500, "frequency": "weekly", "requiredLevel": 245 }, - "Chaos": { "price": 92450000, "frequency": "weekly", "requiredLevel": 245 } + "Normal": { "price": 59535000, "frequency": "weekly", "requiredLevel": 245 }, + "Chaos": { "price": 112789000, "frequency": "weekly", "requiredLevel": 245 } }, "Verus Hilla": { - "Normal": { "price": 89520000, "frequency": "weekly", "requiredLevel": 250 }, - "Hard": { "price": 110450000, "frequency": "weekly", "requiredLevel": 250 } + "Normal": { "price": 116376000, "frequency": "weekly", "requiredLevel": 250 }, + "Hard": { "price": 152421000, "frequency": "weekly", "requiredLevel": 250 } }, "Darknell": { - "Normal": { "price": 52812500, "frequency": "weekly", "requiredLevel": 255 }, - "Hard": { "price": 96800000, "frequency": "weekly", "requiredLevel": 255 } + "Normal": { "price": 63375000, "frequency": "weekly", "requiredLevel": 255 }, + "Hard": { "price": 152421000, "frequency": "weekly", "requiredLevel": 255 } }, "Black Mage": { - "Hard": { "price": 500000000, "frequency": "monthly", "requiredLevel": 255 }, - "Extreme": { "price": 2000000000, "frequency": "monthly", "requiredLevel": 255 } + "Hard": { "price": 900000000, "frequency": "monthly", "requiredLevel": 255 }, + "Extreme": { "price": 3600000000, "frequency": "monthly", "requiredLevel": 255 } }, "Chosen Seren": { - "Normal": { "price": 133687500, "frequency": "weekly", "requiredLevel": 260 }, - "Hard": { "price": 151250000, "frequency": "weekly", "requiredLevel": 260 }, - "Extreme": { "price": 605000000, "frequency": "weekly", "requiredLevel": 260 } + "Normal": { "price": 177804375, "frequency": "weekly", "requiredLevel": 260 }, + "Hard": { "price": 219312000, "frequency": "weekly", "requiredLevel": 260 }, + "Extreme": { "price": 847000000, "frequency": "weekly", "requiredLevel": 260 } }, "Kalos": { - "Easy": { "price": 150000000, "frequency": "weekly", "requiredLevel": 265 }, - "Normal": { "price": 200000000, "frequency": "weekly", "requiredLevel": 265 }, - "Chaos": { "price": 400000000, "frequency": "weekly", "requiredLevel": 265 }, - "Extreme": { "price": 800000000, "frequency": "weekly", "requiredLevel": 265 } + "Easy": { "price": 187500000, "frequency": "weekly", "requiredLevel": 265 }, + "Normal": { "price": 260000000, "frequency": "weekly", "requiredLevel": 265 }, + "Chaos": { "price": 520000000, "frequency": "weekly", "requiredLevel": 265 }, + "Extreme": { "price": 1040000000, "frequency": "weekly", "requiredLevel": 265 } }, "Kaling": { - "Easy": { "price": 165000000, "frequency": "weekly", "requiredLevel": 275 }, - "Normal": { "price": 230000000, "frequency": "weekly", "requiredLevel": 275 }, - "Hard": { "price": 460000000, "frequency": "weekly", "requiredLevel": 275 }, - "Extreme": { "price": 920000000, "frequency": "weekly", "requiredLevel": 275 } + "Easy": { "price": 206250000, "frequency": "weekly", "requiredLevel": 275 }, + "Normal": { "price": 301300000, "frequency": "weekly", "requiredLevel": 275 }, + "Hard": { "price": 598000000, "frequency": "weekly", "requiredLevel": 275 }, + "Extreme": { "price": 1205200000, "frequency": "weekly", "requiredLevel": 275 } }, "Ranmaru": { "Normal": { "price": 840500, "frequency": "daily", "requiredLevel": 120 }, diff --git a/src/app/bosses/tracker/components/BossTable.tsx b/src/app/bosses/tracker/components/BossTable.tsx index 6959b09..8c3f9a8 100644 --- a/src/app/bosses/tracker/components/BossTable.tsx +++ b/src/app/bosses/tracker/components/BossTable.tsx @@ -4,7 +4,7 @@ import { useCharacters } from "@context/account"; import bosses from "@data/bosses.json"; import { Input } from "@hyoretsu/react-components"; import copyObject from "@utils/copyObject"; -import { BossDifficulties, BossFrequency, BossRunInfo, Bosses } from "maple-simulator"; +import type { BossDifficulties, BossFrequency, BossRunInfo, Bosses } from "maple-simulator"; import { useCallback, useMemo } from "react"; import styles from "../styles.module.scss"; @@ -61,69 +61,43 @@ export default function BossTable() { ); }, [currentCharacter]); - const bossAvailability = useMemo>(() => { - return parsedBosses.reduce((availableObj, [boss, difficulties]) => { - for (const [difficulty] of difficulties) { - const difficultyBoss = `${difficulty} ${boss}`; - - Object.assign(availableObj, { [difficultyBoss]: true }); + const updateRoutine = useCallback( + (newBossData: Record>) => { + const newBossDataEntries = Object.entries(newBossData); + if (newBossDataEntries.length > 1) { + throw new Error("You must update bossing routines one by one."); + } - if (!Object.keys(currentCharacter.bossingRoutine).find(routineBoss => routineBoss.match(boss))) { - continue; - } + const newRoutine = copyObject(currentCharacter.bossingRoutine); + const [difficultyBoss, newData] = newBossDataEntries[0]; - const sameBosses = Object.entries(availableObj).filter(([givenBoss]) => { - const [givenDifficulty, givenBossName] = givenBoss.split(/(?<=^\S+)\s/g); + if (Object.entries(newData).length === 0) { + delete newRoutine[difficultyBoss]; + } else { + const newBoss = difficultyBoss.split(" ").slice(1).join(" "); - return ( - givenBossName === boss && - // @ts-ignore - bosses[givenBossName][givenDifficulty].frequency === bosses[boss][difficulty].frequency - ); - }); + for (const [diffBoss] of Object.entries(newRoutine)) { + const oldBoss = diffBoss.split(" ").slice(1).join(" "); - if ( - sameBosses.length < 2 || - !sameBosses.find(([givenBoss]) => - Object.keys(currentCharacter.bossingRoutine).find(routineBoss => routineBoss === givenBoss), - ) - ) { - continue; + if (oldBoss === newBoss) { + delete newRoutine[diffBoss]; + } } - for (const [boss] of sameBosses) { - Object.assign(availableObj, { [boss]: !!currentCharacter.bossingRoutine[boss] }); - } + Object.assign(newRoutine, { + [difficultyBoss]: { + ...newRoutine[difficultyBoss], + ...newData, + }, + }); } - return availableObj; - }, {}); - }, [currentCharacter, parsedBosses]); - - const updateRoutine = (newBossData: Record>) => { - const newBossDataEntries = Object.entries(newBossData); - if (newBossDataEntries.length > 1) { - throw new Error("You must update bossing routines one by one."); - } - - const newRoutine = copyObject(currentCharacter.bossingRoutine); - const [difficultyBoss, newData] = newBossDataEntries[0]; - - if (Object.entries(newData).length === 0) { - delete newRoutine[difficultyBoss]; - } else { - Object.assign(newRoutine, { - [difficultyBoss]: { - ...newRoutine[difficultyBoss], - ...newData, - }, + updateCharacter(currentCharacter.id, { + bossingRoutine: newRoutine, }); - } - - updateCharacter(currentCharacter.id, { - bossingRoutine: newRoutine, - }); - }; + }, + [currentCharacter.bossingRoutine, currentCharacter.id, updateCharacter], + ); const report = useMemo( () => @@ -225,12 +199,11 @@ export default function BossTable() { const difficultyBoss = `${difficulty} ${boss}`; if ( - !bossAvailability[difficultyBoss] || - (!currentCharacter.bossingRoutine[difficultyBoss] && - report.crystals + - // @ts-ignore - (bosses[boss][difficulty].frequency === "daily" ? 7 : 1) > - maxAmount) + !currentCharacter.bossingRoutine[difficultyBoss] && + report.crystals + + // @ts-ignore + (bosses[boss][difficulty].frequency === "daily" ? 7 : 1) > + maxAmount ) { return; } @@ -242,10 +215,10 @@ export default function BossTable() { partySize: 1, timeTaken: 0, ...runInfo, - }, + }, }); }, - [bossAvailability, currentCharacter, report, updateRoutine], + [currentCharacter, report, updateRoutine], ); return ( @@ -263,7 +236,7 @@ export default function BossTable() { } return str; - }, " in ") + }, " in ") : ""}
( {`${ @@ -272,7 +245,7 @@ export default function BossTable() { notation: "compact", minimumFractionDigits: 2, maximumFractionDigits: 2, - }) + }) .format( Number( Math.round( @@ -290,7 +263,7 @@ export default function BossTable() { ? characterReport.notCounted ? `, ${characterReport.notCounted}/${ characterReport.notCounted + characterReport.counted - } bosses not counted` + } bosses not counted` : `, ${characterReport.counted} bosses total` : `${characterReport.timedIncome ? ", " : ""}${characterReport.notCounted} bosses total` }`} @@ -320,7 +293,7 @@ export default function BossTable() { {} as Record, ), ).map(([frequency, difficultyArr]) => ( -
+
{frequency.slice(0, 1).toUpperCase() + frequency.slice(1)}
@@ -355,7 +328,7 @@ export default function BossTable() { ? { border } : { padding: "calc(0.25rem + 2px) 2px", - }), + }), }} > {difficulty} @@ -439,8 +412,7 @@ export default function BossTable() {

You are making a total of {formatNumber(report.timedIncome)} mesos in {Math.round(report.time[0])}h - {Math.round(report.time[1])}m - {Math.round(report.time[2])}s among {report.timedBosses}{" "} + {Math.round(report.time[1])}m{Math.round(report.time[2])}s among {report.timedBosses}{" "} {report.timedBosses > 1 ? "bosses" : "boss"}.
For comparison, that's equal to{" "} diff --git a/src/context/account.tsx b/src/context/account.tsx index bf91c4d..3476eab 100644 --- a/src/context/account.tsx +++ b/src/context/account.tsx @@ -1,6 +1,14 @@ "use client"; +import bosses from "@data/bosses.json"; import copyObject from "@utils/copyObject"; -import type { Account, BossingRoutine, Character, CharacterEquip, CharacterEquips } from "maple-simulator"; +import type { + Account, + BossFrequency, + BossingRoutine, + Character, + CharacterEquip, + CharacterEquips, +} from "maple-simulator"; import { type PropsWithChildren, createContext, @@ -81,10 +89,49 @@ const defaultSymbol = { const bumpCharacter = (character: Character): boolean => { let changed = false; + const bossInfo: Record = {}; + for (const [prop, value] of Object.entries(defaultCharacter)) { - if (prop === "bossingRoutine" && !character.bossingRoutine) { - character.bossingRoutine = copyObject(value) as BossingRoutine; - changed = true; + if (prop === "bossingRoutine") { + if (!character.bossingRoutine) { + character.bossingRoutine = copyObject(value) as BossingRoutine; + changed = true; + } + + const bossingRoutine = Object.entries(character.bossingRoutine); + + for (const [difficultyBoss] of bossingRoutine) { + if (bossInfo[difficultyBoss]) { + continue; + } + + const [difficulty, boss] = difficultyBoss.split(/(?<=^\S+)\s/g); + + // @ts-expect-error: JSON's are strongly typed + bossInfo[difficultyBoss] = bosses[boss][difficulty]; + } + + bossingRoutine.sort(([difficultyBossA, infoA], [difficultyBossB, infoB]) => { + return ( + bossInfo[difficultyBossB].price / (infoB?.partySize || 1) - + bossInfo[difficultyBossA].price / (infoA?.partySize || 1) + ); + }); + + let weeklyCounter = 0; + for (const [difficultyBoss] of bossingRoutine) { + if (bossInfo[difficultyBoss].frequency !== "weekly") { + continue; + } + + if (weeklyCounter >= 14) { + delete character.bossingRoutine[difficultyBoss]; + changed = true; + continue; + } + + weeklyCounter += 1; + } } else if (prop === "symbols") { if (!character.symbols) { character.symbols = copyObject(defaultCharacter.symbols); @@ -334,7 +381,8 @@ export function AccountProvider({ children }: PropsWithChildren) { const updateCharacter = useCallback((id, updatedCharacter) => { setAccount(old => { const newAccount = copyObject(old); - const character = newAccount.characters.find(({ id: characterId }) => characterId === id) as Character; + const characterIndex = newAccount.characters.findIndex(({ id: characterId }) => characterId === id); + const character = newAccount.characters[characterIndex]; if (updatedCharacter.equips) { Object.values(updatedCharacter.equips).map(equipPre => { @@ -366,7 +414,11 @@ export function AccountProvider({ children }: PropsWithChildren) { } Object.assign(character, updatedCharacter); - bumpCharacter(character); + const changed = bumpCharacter(character); + if (changed) { + newAccount.characters[characterIndex] = character; + } + localStorage.setItem(`@maple-simulator:character_${character.id}`, JSON.stringify(character)); return newAccount;