]> git.localhorst.tv Git - alttp.git/commitdiff
clean up manual tracking
authorDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 25 Mar 2024 17:52:18 +0000 (18:52 +0100)
committerDaniel Karbach <daniel.karbach@localhorst.tv>
Mon, 25 Mar 2024 17:52:18 +0000 (18:52 +0100)
resources/js/components/tracker/Dungeons.js
resources/js/components/tracker/Map.js
resources/js/components/tracker/ToggleIcon.js
resources/js/helpers/tracker.js

index 07b66389dd0b7f7e5830c09edcca060af7dd8c53..08a581f209a1428bbf12f0cf002239f14a0be28c 100644 (file)
@@ -2,6 +2,10 @@ import React from 'react';
 
 import CountDisplay from './CountDisplay';
 import ToggleIcon from './ToggleIcon';
+import {
+       getDungeonAcquiredSKs,
+       getDungeonRemainingItems,
+} from '../../helpers/tracker';
 import { useTracker } from '../../hooks/tracker';
 
 const Dungeons = () => {
@@ -24,7 +28,7 @@ const Dungeons = () => {
                                                controller={ToggleIcon.dungeonCountController(dungeon, dungeon.sk)}
                                                icons={['small-key']}
                                        />
-                                       <CountDisplay count={state[`${dungeon.id}-small-key`] || 0} />
+                                       <CountDisplay count={getDungeonAcquiredSKs(state, dungeon)} />
                                </span>
                                <ToggleIcon
                                        controller={ToggleIcon.dungeonController(dungeon)}
@@ -32,10 +36,10 @@ const Dungeons = () => {
                                />
                                <span className="dungeon-checks">
                                        <ToggleIcon
-                                               controller={ToggleIcon.dungeonCheckController(dungeon, dungeon.items)}
+                                               controller={ToggleIcon.dungeonCheckController(dungeon)}
                                                icons={['open-chest', 'chest']}
                                        />
-                                       <CountDisplay count={dungeon.items - (state[`${dungeon.id}-checks`] || 0)} />
+                                       <CountDisplay count={getDungeonRemainingItems(state, dungeon)} />
                                </span>
                                {dungeon.boss ?
                                        <ToggleIcon
index b2685f873d6776814e00db66ff2cc6c225d51b03..cfae29c4b4a4875e0c71e087b7f7456ee511d014 100644 (file)
@@ -3,12 +3,20 @@ import React from 'react';
 import { useTranslation } from 'react-i18next';
 
 import {
+       addDungeonCheck,
        clearAll,
-       decrement,
+       completeDungeonChecks,
+       countRemainingLocations,
+       getDungeonClearedItems,
+       getDungeonRemainingItems,
+       hasClearedLocations,
        hasDungeonBoss,
-       increment,
+       hasDungeonPrize,
        isDungeonCleared,
-       toggleBoolean,
+       removeDungeonCheck,
+       resetDungeonChecks,
+       setBossDefeated,
+       setPrizeAcquired,
        unclearAll,
 } from '../../helpers/tracker';
 import { useTracker } from '../../hooks/tracker';
@@ -637,8 +645,8 @@ const Location = ({ number, l, size }) => {
        >
                <title>{t(`tracker.location.${l.id}`)}</title>
                <rect className="box" x="0" y="0" />
-               {number && l.cleared < l.total ?
-                       <text className="text" x="0" y="0">{Math.max(0, l.total - l.cleared)}</text>
+               {number && l.remaining ?
+                       <text className="text" x="0" y="0">{l.remaining}</text>
                : null}
        </g>;
 };
@@ -649,8 +657,8 @@ Location.propTypes = {
                id: PropTypes.string,
                x: PropTypes.number,
                y: PropTypes.number,
-               cleared: PropTypes.number,
-               total: PropTypes.number,
+               number: PropTypes.number,
+               remaining: PropTypes.number,
                status: PropTypes.string,
                handlePrimary: PropTypes.func,
                handleSecondary: PropTypes.func,
@@ -682,8 +690,7 @@ const Map = () => {
 
        const mapDungeon = React.useCallback(dungeon => {
                const definition = dungeons.find(d => d.id === dungeon.id);
-               const cleared = state[`${dungeon.id}-checks`] || 0;
-               const total = definition.items;
+               const remaining = getDungeonRemainingItems(state, definition);
                let status = 'available';
                if (isDungeonCleared(state, definition)) {
                        status = 'cleared';
@@ -691,65 +698,74 @@ const Map = () => {
                return {
                        ...dungeon,
                        status,
-                       cleared,
-                       total,
+                       remaining,
                        handlePrimary: () => {
-                               if (['ct', 'gt'].includes(dungeon.id) && cleared === total) {
-                                       if (hasDungeonBoss(state, dungeon)) {
-                                               // reset
-                                               setState(s => ({
-                                                       ...s,
-                                                       [`${dungeon.id}-checks`]: 0,
-                                                       [`${dungeon.id}-boss-defeated`]: false,
-                                               }));
-                                       } else {
-                                               setState(toggleBoolean(`${dungeon.id}-boss-defeated`));
+                               if (getDungeonRemainingItems(state, definition)) {
+                                       setState(addDungeonCheck(definition));
+                               } else if (
+                                       !hasDungeonBoss(state, definition) || !hasDungeonPrize(state, definition)
+                               ) {
+                                       if (definition.boss) {
+                                               setState(setBossDefeated(definition, true));
+                                       }
+                                       if (definition.prize) {
+                                               setState(setPrizeAcquired(definition, true));
                                        }
                                } else {
-                                       setState(increment(`${dungeon.id}-checks`, total));
+                                       setState(resetDungeonChecks(definition));
+                                       if (definition.boss) {
+                                               setState(setBossDefeated(definition, false));
+                                       }
+                                       if (definition.prize) {
+                                               setState(setPrizeAcquired(definition, false));
+                                       }
                                }
                        },
                        handleSecondary: () => {
-                               if (['ct', 'gt'].includes(dungeon.id) &&
-                                       (hasDungeonBoss(state, dungeon) || !cleared)
-                               ) {
-                                       if (hasDungeonBoss(state, dungeon)) {
-                                               setState(toggleBoolean(`${dungeon.id}-boss-defeated`));
-                                       } else {
-                                               setState(s => ({
-                                                       ...s,
-                                                       [`${dungeon.id}-checks`]: total,
-                                                       [`${dungeon.id}-boss-defeated`]: true,
-                                               }));
+                               if (isDungeonCleared(state, definition)) {
+                                       if (definition.items) {
+                                               setState(removeDungeonCheck(definition));
                                        }
+                                       if (definition.boss) {
+                                               setState(setBossDefeated(definition, false));
+                                       }
+                                       if (definition.prize) {
+                                               setState(setPrizeAcquired(definition, false));
+                                       }
+                               } else if (getDungeonClearedItems(state, definition)) {
+                                       setState(removeDungeonCheck(definition));
                                } else {
-                                       setState(decrement(`${dungeon.id}-checks`, total));
+                                       setState(completeDungeonChecks(definition));
+                                       if (definition.boss) {
+                                               setState(setBossDefeated(definition, true));
+                                       }
+                                       if (definition.prize) {
+                                               setState(setPrizeAcquired(definition, true));
+                                       }
                                }
                        },
                };
        }, [dungeons, setState, state]);
 
        const mapLocation = React.useCallback(loc => {
-               const cleared = loc.checks.reduce((acc, cur) => state[cur] ? acc + 1 : acc, 0);
-               const total = loc.checks.length;
+               const remaining = countRemainingLocations(state, loc.checks);
                let status = 'available';
-               if (cleared === total) {
+               if (hasClearedLocations(state, loc.checks)) {
                        status = 'cleared';
                }
                return {
                        ...loc,
-                       cleared,
-                       total,
+                       remaining,
                        status,
                        handlePrimary: () => {
-                               if (cleared < total) {
+                               if (remaining) {
                                        setState(clearAll(loc.checks));
                                } else {
                                        setState(unclearAll(loc.checks));
                                }
                        },
                        handleSecondary: () => {
-                               if (cleared < total) {
+                               if (remaining) {
                                        setState(clearAll(loc.checks));
                                } else {
                                        setState(unclearAll(loc.checks));
index 3f6af9641c0926acb2bf31b1cd8618e74ffe5c3d..f7cc0744b81f22619634fecfc047cf66451b098a 100644 (file)
@@ -3,14 +3,18 @@ import React from 'react';
 
 import ZeldaIcon from '../common/ZeldaIcon';
 import {
+       addDungeonCheck,
        decrement,
        getDungeonBoss,
+       getDungeonRemainingItems,
        getDungeonPrize,
        hasDungeonBoss,
        hasDungeonPrize,
        highestActive,
        increment,
+       removeDungeonCheck,
        toggleBoolean,
+       toggleBossDefeated,
 } from '../../helpers/tracker';
 import { useTracker } from '../../hooks/tracker';
 
@@ -110,23 +114,23 @@ ToggleIcon.dungeonBossController = (dungeon) => ({
        handlePrimary: dungeon.bosses.length > 1
                ? nextString(`${dungeon.id}-boss`)
                : (state, setState) => {
-                       setState(toggleBoolean(`${dungeon.id}-boss-defeated`));
+                       setState(toggleBossDefeated(dungeon));
                },
        handleSecondary: dungeon.bosses.length > 1 ?
                previousString(`${dungeon.id}-boss`)
                : (state, setState) => {
-                       setState(toggleBoolean(`${dungeon.id}-boss-defeated`));
+                       setState(toggleBossDefeated(dungeon));
                },
 });
 
-ToggleIcon.dungeonCheckController = (dungeon, max) => ({
-       getActive: (state, icons) => state[`${dungeon.id}-checks`] < max ? icons[1] : null,
+ToggleIcon.dungeonCheckController = (dungeon) => ({
+       getActive: (state, icons) => getDungeonRemainingItems(state, dungeon) ? icons[1] : null,
        getDefault: firstIcon,
        handlePrimary: (state, setState) => {
-               setState(increment(`${dungeon.id}-checks`, max));
+               setState(addDungeonCheck(dungeon));
        },
        handleSecondary: (state, setState) => {
-               setState(decrement(`${dungeon.id}-checks`, max));
+               setState(removeDungeonCheck(dungeon));
        },
 });
 
index 92508d46f1bc9434b97e641c8132a4fd94f0a095..bc18847fcc10e47ad7f0a8c8405b64ce0323a37b 100644 (file)
@@ -1598,24 +1598,59 @@ export const unclearAll = names => state => {
        return { ...state, ...changes };
 };
 
-export const hasDungeonBoss = (state, dungeon) => !!state[`${dungeon.id}-boss-defeated`];
+export const countClearedLocations = (state, locations) =>
+       locations.reduce((acc, cur) => state[cur] ? acc + 1 : acc, 0);
+
+export const hasClearedLocations = (state, locations) =>
+       countClearedLocations(state, locations) === locations.length;
+
+export const countRemainingLocations = (state, locations) =>
+       locations.reduce((acc, cur) => state[cur] ? acc : acc + 1, 0);
+
+export const hasDungeonBoss = (state, dungeon) =>
+       !dungeon.boss || !!state[`${dungeon.id}-boss-defeated`];
 
 export const getDungeonBoss = (state, dungeon) =>
        state[`${dungeon.id}-boss`] || dungeon.boss || null;
 
-export const hasDungeonPrize = (state, dungeon) => !!state[`${dungeon.id}-prize-acquired`];
+export const hasDungeonPrize = (state, dungeon) =>
+       !dungeon.prize || !!state[`${dungeon.id}-prize-acquired`];
 
 export const getDungeonPrize = (state, dungeon) => state[`${dungeon.id}-prize`] || null;
 
+export const getDungeonClearedItems = (state, dungeon) => state[`${dungeon.id}-checks`] || 0;
+
+export const getDungeonRemainingItems = (state, dungeon) =>
+       Math.max(0, dungeon.items - getDungeonClearedItems(state, dungeon));
+
+export const getDungeonAcquiredSKs = (state, dungeon) => state[`${dungeon.id}-small-key`] || 0;
+
 export const isDungeonCleared = (state, dungeon) => {
-       const cleared = state[`${dungeon.id}-checks`] || 0;
-       const total = dungeon.items;
-       const hasItems = cleared >= total;
-       const hasBoss = !dungeon.boss || hasDungeonBoss(state, dungeon);
-       const hasPrize = !dungeon.porize || hasDungeonPrize(state, dungeon);
+       const hasItems = !getDungeonRemainingItems(state, dungeon);
+       const hasBoss = hasDungeonBoss(state, dungeon);
+       const hasPrize = hasDungeonPrize(state, dungeon);
        return hasItems && hasBoss && hasPrize;
 };
 
+export const toggleBossDefeated = dungeon => toggleBoolean(`${dungeon.id}-boss-defeated`);
+
+export const setBossDefeated = (dungeon, defeated) =>
+       state => ({ ...state, [`${dungeon.id}-boss-defeated`]: !!defeated });
+
+export const togglePrizeAcquired = dungeon => toggleBoolean(`${dungeon.id}-prize-acquired`);
+
+export const setPrizeAcquired = (dungeon, acquired) =>
+       state => ({ ...state, [`${dungeon.id}-prize-acquired`]: !!acquired });
+
+export const addDungeonCheck = dungeon => increment(`${dungeon.id}-checks`, dungeon.items);
+
+export const removeDungeonCheck = dungeon => decrement(`${dungeon.id}-checks`, dungeon.items);
+
+export const resetDungeonChecks = dungeon => state => ({ ...state, [`${dungeon.id}-checks`]: 0 });
+
+export const completeDungeonChecks = dungeon =>
+       state => ({ ...state, [`${dungeon.id}-checks`]: dungeon.items });
+
 export const makeEmptyState = () => {
        const state = {};
        BOOLEAN_STATES.forEach(p => {