1 import PropTypes from 'prop-types';
2 import React from 'react';
3 import { useTranslation } from 'react-i18next';
5 import { useTracker } from '../../hooks/tracker';
35 const LW_LOCATIONS = [
50 'blinds-hut-far-left',
51 'blinds-hut-far-right',
130 id: 'floating-island',
146 id: 'graveyard-ledge',
190 id: 'lake-hylia-island',
214 id: 'lost-woods-hideout',
216 'lost-woods-hideout',
246 id: 'mini-moldorm-cave',
249 'mini-moldorm-right',
250 'mini-moldorm-far-left',
251 'mini-moldorm-far-right',
276 'paradox-lower-far-left',
277 'paradox-lower-left',
278 'paradox-lower-right',
279 'paradox-lower-far-right',
281 'paradox-upper-left',
282 'paradox-upper-right',
355 id: 'spec-rock-cave',
379 id: 'waterfall-fairy',
381 'waterfall-fairy-left',
382 'waterfall-fairy-right',
405 const DW_DUNGEONS = [
448 const DW_LOCATIONS = [
524 id: 'hookshot-cave-bonk',
571 'pyramid-fairy-left',
572 'pyramid-fairy-right',
597 'super-bunny-bottom',
604 const Location = ({ l, size }) => {
605 const { t } = useTranslation();
607 const classNames = ['location', `status-${l.status}`];
609 classNames.push(`size-${size}`);
612 return <rect className={classNames.join(' ')} x={l.x} y={l.y}>
613 <title>{t(`tracker.location.${l.id}`)}</title>
617 Location.propTypes = {
619 id: PropTypes.string,
622 cleared: PropTypes.number,
623 total: PropTypes.number,
624 status: PropTypes.string,
626 size: PropTypes.string,
630 const { dungeons, state } = useTracker();
632 const mapDungeon = React.useCallback(dungeon => {
633 const definition = dungeons.find(d => d.id === dungeon.id);
634 const cleared = state[`${dungeon.id}-checks`] || 0;
635 const total = definition.items;
636 let status = 'available';
637 if (cleared === total) {
638 if (['ct', 'gt'].includes(dungeon.id)) {
639 if (state[`${dungeon.id}-boss-defeated`]) {
652 }, [dungeons, state]);
654 const mapLocation = React.useCallback(loc => {
655 const cleared = loc.checks.reduce((acc, cur) => state[cur] ? acc + 1 : acc, 0);
656 const total = loc.checks.length;
657 let status = 'available';
658 if (cleared === total) {
669 const lwDungeons = React.useMemo(() => LW_DUNGEONS.map(mapDungeon), [mapDungeon]);
670 const lwLocations = React.useMemo(() => LW_LOCATIONS.map(mapLocation), [mapLocation]);
672 const dwDungeons = React.useMemo(() => DW_DUNGEONS.map(mapDungeon), [mapDungeon]);
673 const dwLocations = React.useMemo(() => DW_LOCATIONS.map(mapLocation), [mapLocation]);
675 return <div className="tracker-map">
677 xmlns="http://www.w3.org/2000/svg"
683 <g className="light-world">
684 <g className="background">
690 href="/media/alttp/map/lw_files/9/0_0.png"
697 href="/media/alttp/map/lw_files/9/1_0.png"
704 href="/media/alttp/map/lw_files/9/0_1.png"
711 href="/media/alttp/map/lw_files/9/1_1.png"
714 <g className="locations">
715 {lwLocations.map(l =>
716 <Location key={l.id} l={l} />
719 <Location key={l.id} l={l} size="lg" />
723 <g className="dark-world" transform="translate(1 0)">
724 <g className="background">
730 href="/media/alttp/map/dw_files/9/0_0.png"
737 href="/media/alttp/map/dw_files/9/1_0.png"
744 href="/media/alttp/map/dw_files/9/0_1.png"
751 href="/media/alttp/map/dw_files/9/1_1.png"
754 <g className="locations">
755 {dwLocations.map(l =>
756 <Location key={l.id} l={l} />
759 <Location key={l.id} l={l} size="lg" />