diff --git a/.github/workflows/azure-static-web-apps-lively-pebble-0b97b301e.yml b/.github/workflows/azure-static-web-apps-lively-pebble-0b97b301e.yml new file mode 100644 index 0000000..e35c4be --- /dev/null +++ b/.github/workflows/azure-static-web-apps-lively-pebble-0b97b301e.yml @@ -0,0 +1,46 @@ +name: Azure Static Web Apps CI/CD + +on: + push: + branches: + - maps + pull_request: + types: [opened, synchronize, reopened, closed] + branches: + - maps + +jobs: + build_and_deploy_job: + if: github.event_name == 'push' || (github.event_name == 'pull_request' && github.event.action != 'closed') + runs-on: ubuntu-latest + name: Build and Deploy Job + steps: + - uses: actions/checkout@v3 + with: + submodules: true + lfs: false + - name: Build And Deploy + id: builddeploy + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LIVELY_PEBBLE_0B97B301E }} + repo_token: ${{ secrets.GITHUB_TOKEN }} # Used for Github integrations (i.e. PR comments) + action: "upload" + ###### Repository/Build Configurations - These values can be configured to match your app requirements. ###### + # For more information regarding Static Web App workflow configurations, please visit: https://aka.ms/swaworkflowconfig + app_location: "/" # App source code path + api_location: "" # Api source code path - optional + output_location: "build" # Built app content directory - optional + ###### End of Repository/Build Configurations ###### + + close_pull_request_job: + if: github.event_name == 'pull_request' && github.event.action == 'closed' + runs-on: ubuntu-latest + name: Close Pull Request Job + steps: + - name: Close Pull Request + id: closepullrequest + uses: Azure/static-web-apps-deploy@v1 + with: + azure_static_web_apps_api_token: ${{ secrets.AZURE_STATIC_WEB_APPS_API_TOKEN_LIVELY_PEBBLE_0B97B301E }} + action: "close" diff --git a/package.json b/package.json index 99062f7..163663b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "lynn", - "version": "22.2.az", + "version": "23.0.0", "private": true, "dependencies": { "@date-io/dayjs": "^2.16.0", diff --git a/public/assets/maps/bsf.png b/public/assets/maps/bsf.png new file mode 100644 index 0000000..75e9085 Binary files /dev/null and b/public/assets/maps/bsf.png differ diff --git a/public/assets/maps/hydatos.png b/public/assets/maps/hydatos.png new file mode 100644 index 0000000..dc2d67c Binary files /dev/null and b/public/assets/maps/hydatos.png differ diff --git a/public/assets/maps/markers/aetheryte.png b/public/assets/maps/markers/aetheryte.png new file mode 100644 index 0000000..fb10cf1 Binary files /dev/null and b/public/assets/maps/markers/aetheryte.png differ diff --git a/public/assets/maps/markers/baportal.png b/public/assets/maps/markers/baportal.png new file mode 100644 index 0000000..ddac20a Binary files /dev/null and b/public/assets/maps/markers/baportal.png differ diff --git a/public/assets/maps/markers/box.png b/public/assets/maps/markers/box.png new file mode 100644 index 0000000..517a268 Binary files /dev/null and b/public/assets/maps/markers/box.png differ diff --git a/public/assets/maps/markers/bsfFragment.png b/public/assets/maps/markers/bsfFragment.png new file mode 100644 index 0000000..fe4b226 Binary files /dev/null and b/public/assets/maps/markers/bsfFragment.png differ diff --git a/public/assets/maps/markers/coffer.png b/public/assets/maps/markers/coffer.png new file mode 100644 index 0000000..aa7fa1a Binary files /dev/null and b/public/assets/maps/markers/coffer.png differ diff --git a/public/assets/maps/markers/elemental.png b/public/assets/maps/markers/elemental.png new file mode 100644 index 0000000..f6cba43 Binary files /dev/null and b/public/assets/maps/markers/elemental.png differ diff --git a/public/assets/maps/markers/fate-boss.png b/public/assets/maps/markers/fate-boss.png new file mode 100644 index 0000000..7589454 Binary files /dev/null and b/public/assets/maps/markers/fate-boss.png differ diff --git a/public/assets/maps/markers/fate-defense.png b/public/assets/maps/markers/fate-defense.png new file mode 100644 index 0000000..6b298a6 Binary files /dev/null and b/public/assets/maps/markers/fate-defense.png differ diff --git a/public/assets/maps/markers/fate-duel.png b/public/assets/maps/markers/fate-duel.png new file mode 100644 index 0000000..9e1294f Binary files /dev/null and b/public/assets/maps/markers/fate-duel.png differ diff --git a/public/assets/maps/markers/fate-enemies.png b/public/assets/maps/markers/fate-enemies.png new file mode 100644 index 0000000..6004a29 Binary files /dev/null and b/public/assets/maps/markers/fate-enemies.png differ diff --git a/public/assets/maps/markers/fate-gather.png b/public/assets/maps/markers/fate-gather.png new file mode 100644 index 0000000..88b7254 Binary files /dev/null and b/public/assets/maps/markers/fate-gather.png differ diff --git a/public/assets/maps/markers/fate-nm.png b/public/assets/maps/markers/fate-nm.png new file mode 100644 index 0000000..09cba96 Binary files /dev/null and b/public/assets/maps/markers/fate-nm.png differ diff --git a/public/assets/maps/markers/fate-wave.png b/public/assets/maps/markers/fate-wave.png new file mode 100644 index 0000000..cae3ae1 Binary files /dev/null and b/public/assets/maps/markers/fate-wave.png differ diff --git a/public/assets/maps/markers/fieldNote.png b/public/assets/maps/markers/fieldNote.png new file mode 100644 index 0000000..fe2b4af Binary files /dev/null and b/public/assets/maps/markers/fieldNote.png differ diff --git a/public/assets/maps/markers/garleanFabric.png b/public/assets/maps/markers/garleanFabric.png new file mode 100644 index 0000000..c9eb966 Binary files /dev/null and b/public/assets/maps/markers/garleanFabric.png differ diff --git a/public/assets/maps/markers/logos-manipulator.png b/public/assets/maps/markers/logos-manipulator.png new file mode 100644 index 0000000..4bd1124 Binary files /dev/null and b/public/assets/maps/markers/logos-manipulator.png differ diff --git a/public/assets/maps/markers/lostfindscache.png b/public/assets/maps/markers/lostfindscache.png new file mode 100644 index 0000000..d4c25e7 Binary files /dev/null and b/public/assets/maps/markers/lostfindscache.png differ diff --git a/public/assets/maps/markers/magia-melder.png b/public/assets/maps/markers/magia-melder.png new file mode 100644 index 0000000..ffadfa8 Binary files /dev/null and b/public/assets/maps/markers/magia-melder.png differ diff --git a/public/assets/maps/markers/mob.png b/public/assets/maps/markers/mob.png new file mode 100644 index 0000000..4904033 Binary files /dev/null and b/public/assets/maps/markers/mob.png differ diff --git a/public/assets/maps/markers/poi-pin.png b/public/assets/maps/markers/poi-pin.png new file mode 100644 index 0000000..f95ba85 Binary files /dev/null and b/public/assets/maps/markers/poi-pin.png differ diff --git a/public/assets/maps/markers/quest.png b/public/assets/maps/markers/quest.png new file mode 100644 index 0000000..1b82ec2 Binary files /dev/null and b/public/assets/maps/markers/quest.png differ diff --git a/public/assets/maps/markers/repair.png b/public/assets/maps/markers/repair.png new file mode 100644 index 0000000..9c0f61c Binary files /dev/null and b/public/assets/maps/markers/repair.png differ diff --git a/public/assets/maps/markers/shop.png b/public/assets/maps/markers/shop.png new file mode 100644 index 0000000..e19e28a Binary files /dev/null and b/public/assets/maps/markers/shop.png differ diff --git a/public/assets/maps/markers/skirmish.png b/public/assets/maps/markers/skirmish.png new file mode 100644 index 0000000..633c53b Binary files /dev/null and b/public/assets/maps/markers/skirmish.png differ diff --git a/public/assets/maps/markers/trader.png b/public/assets/maps/markers/trader.png new file mode 100644 index 0000000..2fb83a8 Binary files /dev/null and b/public/assets/maps/markers/trader.png differ diff --git a/src/App.jsx b/src/App.jsx index 5020145..f4f3339 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -24,6 +24,7 @@ import ChangelogComponent from './ChangelogComponent'; import DRSNewHolsterMainComponent from './drs/DRSNewHolsterMainComponent'; import DRSRunHolsterCreatorContainerComponent from './drs/create/DRSRunHolsterCreatorContainerComponent'; import BAMorbolMapComponent from './BAMorbolMapComponent'; +import MapPageComponent from './map/MapPageComponent'; export const ColorModeContext = React.createContext({ toggleColorMode: () => { } }); @@ -104,6 +105,15 @@ function WrappedMainComponent({ component, page }) { colorModeContext={ColorModeContext} /> ); + } if (page === 'map') { + return ( + + ); } return ( @@ -194,6 +204,16 @@ const router = createBrowserRouter([ }, ], }, + { + path: '/map', + element: } page="map" />, + children: [ + { + path: '/map/:mapId', + element: } page="map" />, + }, + ], + }, { path: '/weather-finder', element: } page="weatherfinder" />, diff --git a/src/BAPortalMapComponent.jsx b/src/BAPortalMapComponent.jsx index 6be7048..d7f9e9f 100644 --- a/src/BAPortalMapComponent.jsx +++ b/src/BAPortalMapComponent.jsx @@ -1,10 +1,11 @@ import React from 'react'; import { Box } from '@mui/material'; import { Helmet } from 'react-helmet'; +import MapPageComponent from './map/MapPageComponent'; export default function BAPortalMapComponent() { return ( - + @@ -24,7 +25,10 @@ export default function BAPortalMapComponent() { BA Portal Map - forays.info - BA Portal Map + ); diff --git a/src/MainComponent.jsx b/src/MainComponent.jsx index 5d40ac2..5cc49f0 100644 --- a/src/MainComponent.jsx +++ b/src/MainComponent.jsx @@ -15,6 +15,7 @@ export default function MainComponent({ encodedHolster, lostAction, logosAction, + mapId, colorModeContext, }) { /** @@ -83,11 +84,12 @@ export default function MainComponent({ encodedHolster, lostAction, logosAction, + mapId, resetTimer, })} - + { (page !== 'map' && page !== 'portals') ? : null} diff --git a/src/SidebarComponent.jsx b/src/SidebarComponent.jsx index 2ebe69b..f3c18b6 100644 --- a/src/SidebarComponent.jsx +++ b/src/SidebarComponent.jsx @@ -41,6 +41,7 @@ function SidebarComponent({ const handleSidebarClickFromSidebar = useCallback((event, item) => { navigate(`/${item}`); + handleSidebarClick(); }, [navigate, handleSidebarClick]); @@ -85,92 +86,122 @@ function SidebarComponent({ - EUREKA AND BA + OCCULT CRESCENT { handleSidebarClickFromSidebar(e, 'ba'); }} + disabled + onClick={(e) => { handleSidebarClickFromSidebar(e, 'oc'); }} key={uuidv4()} > - BA Loadouts + Coming soon! + + + BOZJA AND DRS + + { handleSidebarClickFromSidebar(e, 'portals'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'drs/holster'); }} key={uuidv4()} > - BA Portal Map + DRS Holsters { handleSidebarClickFromSidebar(e, 'eureka/logos'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'drs/holster/c'); }} key={uuidv4()} > - Logos Action Info + Holster Creator { handleSidebarClickFromSidebar(e, 'eureka/loadout'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'map/bsf'); }} key={uuidv4()} > - Loadout Creator + Bozja Maps handleSidebarForecastClickFromSidebar(e, ResultsFilter.EUREKA_NMS)} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'bozja/lostaction'); }} key={uuidv4()} > - NM Spawn Times + Lost Action Info handleSidebarForecastClickFromSidebar(e, ResultsFilter.EUREKA_FARMS)} + onClick={(e) => handleSidebarForecastClickFromSidebar(e, ResultsFilter.FRAGMENT_FARM)} key={uuidv4()} > - Logogram/Box Farm Times + Fragment Farm Times - BOZJA AND DRS + EUREKA AND BA { handleSidebarClickFromSidebar(e, 'drs/holster'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'ba'); }} key={uuidv4()} > - DRS Holsters + BA Loadouts { handleSidebarClickFromSidebar(e, 'drs/holster/c'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'portals'); }} key={uuidv4()} > - Holster Creator + BA Portal Map { handleSidebarClickFromSidebar(e, 'bozja/lostaction'); }} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'map/hydatos'); }} key={uuidv4()} > - Lost Action Info + Eureka Maps handleSidebarForecastClickFromSidebar(e, ResultsFilter.FRAGMENT_FARM)} + onClick={(e) => { handleSidebarClickFromSidebar(e, 'eureka/logos'); }} key={uuidv4()} > - Fragment Farm Times + Logos Action Info + + + { handleSidebarClickFromSidebar(e, 'eureka/loadout'); }} + key={uuidv4()} + > + + Loadout Creator + + + handleSidebarForecastClickFromSidebar(e, ResultsFilter.EUREKA_NMS)} + key={uuidv4()} + > + + NM Spawn Times + + + handleSidebarForecastClickFromSidebar(e, ResultsFilter.EUREKA_FARMS)} + key={uuidv4()} + > + + Logogram/Box Farm Times diff --git a/src/TimeAndWeatherPopoverComponent.jsx b/src/TimeAndWeatherPopoverComponent.jsx index f29a5d1..6731988 100644 --- a/src/TimeAndWeatherPopoverComponent.jsx +++ b/src/TimeAndWeatherPopoverComponent.jsx @@ -86,6 +86,7 @@ export default function TimeAndWeatherPopoverComponent() { spacing={1} alignItems="center" justifyContent="center" + key={uuidv4()} > {name} @@ -97,33 +98,35 @@ export default function TimeAndWeatherPopoverComponent() { alignItems="center" > {conditions.map((item, index) => ( - - - {dayjs(item.time.getTime()) - .format('h:mm:ss A')} - - - { + + + {dayjs(item.time.getTime()) + .format('h:mm:ss A')} + + + { new EorzeaTime( dayjs(item.time.getTime()) .toDate(), ) .getHours().toLocaleString('en-US', { minimumIntegerDigits: 2 }) } - : - { + : + { new EorzeaTime( dayjs(item.time.getTime()) .toDate(), ) .getMinutes().toLocaleString('en-US', { minimumIntegerDigits: 2 }) } - {' '} - ET - - + {' '} + ET + + )} + key={uuidv4()} > { + handleMouseMove(e); + }, + }); +} + +export default function FullscreenMapComponent({ + mapData, + mapParameters, + displayLabels, + selectedLayers, + handleMouseMove, +}) { + const markers = []; + const annotations = []; + + // Add all json markers to a flat markers array to display on the map + Object.keys(mapData).forEach((markerType) => { + if (selectedLayers.includes(markerType)) { + // Push all markers of this type to the markers array + /** + * Most options for these markers are set in the map's json file. + * - markerIcon: The icon image displayed. Can be overridden for a specific marker with + * iconOverride. + * - circle: If present, draws a circle around the marker. + * (e.g. FATE/Skirmish/CE/NM boundaries) + * - position: Corresponds to the x/y values in-game. Since we're using leaflet (and have + * to pretend that we're using latitude/longitude values), the y value needs to be + * provided as negative. + * + * TODO: Eventually we'll add support for actual tooltips, but for now it just shows + * the marker's name. + * NOTE: For region names, the marker will be slightly offset due to lacking an icon. + */ + markers.push(...(mapData[markerType].waymarks.map((marker) => ( + + + + + + {displayLabels ? marker.name : ''} + + { + mapData[markerType].circle && ( + + ) + } + + )))); + + /** + * Add annotations, if they exist. These are things drawn on the map that aren't associated + * with a specific marker. + */ + if (mapData[markerType].annotations) { + annotations.push(...mapData[markerType].annotations.map((annotation) => { + switch (annotation.type) { + case 'polyline': + return ( + ( + [point.y, point.x] + ))} + /> + ); + case 'largeText': + // TODO: Adjust font size with zoom. Or make these images, maybe? + return ( + ${annotation.text}`, + iconSize: [0, 0], + iconAnchor: [0, 0], + popupAnchor: [0, 0], + tooltipAnchor: [0, 0], + })} + /> + ); + default: + return null; + } + })); + } + } + }); + + return ( + + + + {markers} + {annotations} + + ); +} diff --git a/src/map/MapContainerComponent.css b/src/map/MapContainerComponent.css new file mode 100644 index 0000000..ee04a8c --- /dev/null +++ b/src/map/MapContainerComponent.css @@ -0,0 +1,65 @@ +.full-screen-map { + height: 100%; +} + +.leaflet-tooltip { + background-color: transparent !important; + border: 0px !important; + box-shadow: none !important; + font-size:14px; + font-weight: 700; + color: #fff !important; + text-shadow: 1px 0 0 #000, 0 -1px 0 #000, 0 1px 0 #000, -1px 0 0 #000; +} + +.leaflet-tooltip-left::before { + display: none !important; +} + +.leaflet-tooltip-right::before { + display: none !important; +} + +.map-container { + position: relative; + flex-grow: 1; + touch-action: manipulation; +} + +.map-layer-selector { + position: absolute; + right: 20px; + z-index: 1000; + padding: 10px; + padding-left: 15px; + border-radius: 10px; + width: 280px; + opacity: 0.8; +} + +.map-zone-selector { + position: absolute; + right: 20px; + z-index: 1000; + padding: 10px; + padding-left: 15px; + border-radius: 10px; + width: 320px; + opacity: 0.8; +} + +.layer-selector-button { + position: absolute; + top: 20px; + right: 20px; + z-index: 1010; +} + +.mouse-coordinates { + position: absolute; + bottom: 20px; + left: 20px; + z-index: 1010; + padding: 10px; + border-radius: 10px; +} diff --git a/src/map/MapContainerComponent.jsx b/src/map/MapContainerComponent.jsx new file mode 100644 index 0000000..0d1f88e --- /dev/null +++ b/src/map/MapContainerComponent.jsx @@ -0,0 +1,165 @@ +import React, { useCallback, useMemo } from 'react'; +import { + Box, + Button, + Stack, + Typography, + useTheme, +} from '@mui/material'; +import LayersIcon from '@mui/icons-material/Layers'; +import MapIcon from '@mui/icons-material/Map'; +import ExpandLessIcon from '@mui/icons-material/ExpandLess'; +import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; +import CheckBoxIcon from '@mui/icons-material/CheckBox'; +import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank'; +import AbcIcon from '@mui/icons-material/Abc'; +import './MapContainerComponent.css'; + +import FullscreenMapComponent from './FullscreenMapComponent'; +import MapLayerSelectorComponent from './MapLayerSelectorComponent'; + +// TODO: Attempt to lazy-load these +import bsfMapData from './lib/poi/bsf.json'; +import hydMapData from './lib/poi/hydatos.json'; +import MapZoneSelectorComponent from './MapZoneSelectorComponent'; +// import MapData from './MapData'; + +export default function MapContainerComponent({ mapId, inputSelectedLayers }) { + const theme = useTheme(); + + // TODO: Have a mapping so we can use multiple identifiers for each zone + const mapData = {}; + mapData.hydatos = hydMapData; + mapData.bsf = bsfMapData; + + // const mapDataManager = MapData.getInstance(); + + const [selectedMapId, setSelectedMapId] = React.useState(mapId ?? 'hydatos'); + + const initialSelectedLayers = inputSelectedLayers + ?? mapData[selectedMapId].layers.map((layer) => layer.id); + const [selectedLayers, setSelectedLayers] = React.useState(initialSelectedLayers); + const [displayLayerSelector, setDisplayLayerSelector] = React.useState(false); + const [displayZoneSelector, setDisplayZoneSelector] = React.useState(false); + const [displayLabels, setDisplayLabels] = React.useState(true); + const [mouseCoordinates, setMouseCoordinates] = React.useState({ lat: 1, lon: -1 }); + const availableLayers = mapData[selectedMapId].categories; + + const handleLayerSelectorUpdate = useCallback((newLayers) => { + setSelectedLayers(newLayers); + }, [selectedLayers, setSelectedLayers]); + + const handleZoneSelectorUpdate = useCallback((data) => { + setSelectedMapId(data); + + // Close selector + setDisplayZoneSelector(false); + + // Update current href + window.history.pushState( + {}, + 'FFXIV Field Operations Assistant - forays.info', + `/map/${data}`, + ); + }, [setSelectedMapId, setDisplayZoneSelector]); + + const handleMouseMove = useCallback((e) => { + setMouseCoordinates({ lat: e.latlng.lat, lon: e.latlng.lng }); + }, [setMouseCoordinates]); + + const displayMap = useMemo(() => ( + + ), [displayLabels, selectedMapId, selectedLayers, handleLayerSelectorUpdate, handleMouseMove]); + + return ( + + { displayMap } + { + displayLayerSelector + && ( + + ) + } + { + displayZoneSelector + && ( + + ) + } + + + + + + + + {`${mouseCoordinates.lon.toFixed(1)}, ${(mouseCoordinates.lat * -1.0).toFixed(1)}`} + + + + ); +} + +/** + * Some notes on this: + * - We'll need a layer selector. Probably also need a map switcher. + * - Need to add support for regions as well as points, for CE/FATE boundaries and mob spawn areas. + * - Need to make an inline version of this for the forecast/ section. + */ diff --git a/src/map/MapLayerSelectorComponent.jsx b/src/map/MapLayerSelectorComponent.jsx new file mode 100644 index 0000000..405bd77 --- /dev/null +++ b/src/map/MapLayerSelectorComponent.jsx @@ -0,0 +1,116 @@ +import { + Box, Checkbox, FormControlLabel, FormGroup, + Typography, + useTheme, +} from '@mui/material'; +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars-2'; + +export default function MapLayerSelectorComponent({ + selectedLayers, + availableLayers, + handleLayerSelectorUpdate, +}) { + const theme = useTheme(); + + const checkboxesToDisplay = []; + + // TODO: Fix this error. + // eslint-disable-next-line no-restricted-syntax + for (const category of availableLayers) { + // Push parent checkbox + checkboxesToDisplay.push( + {category.name}} + key={category.name} + control={ + ( + selectedLayers.includes(layer.id))} + indeterminate={ + category.layers.some((layer) => selectedLayers.includes(layer.id)) + && !category.layers.every((layer) => selectedLayers.includes(layer.id)) + } + disabled={!category.enabled} + /> + ) + } + onChange={(e) => { + // TODO: This doesn't work yet, need to see why + const newLayers = [...selectedLayers]; + if (e.target.checked) { + category.layers.forEach((layer) => { + if (!newLayers.includes(layer.id)) { + newLayers.push(layer.id); + } + }); + } else { + category.layers.forEach((layer) => { + const index = newLayers.indexOf(layer.id); + if (index > -1) { + newLayers.splice(index, 1); + } + }); + } + handleLayerSelectorUpdate(newLayers); + }} + />, + ); + + // Push child checkboxes + const categoryLayers = category.layers.map((layer) => ( + + ) + } + label={layer.name} + onChange={(e) => { + const newLayers = [...selectedLayers]; + if (e.target.checked) { + newLayers.push(layer.id); + } else { + const index = newLayers.indexOf(layer.id); + if (index > -1) { + newLayers.splice(index, 1); + } + } + handleLayerSelectorUpdate(newLayers); + }} + /> + )); + + checkboxesToDisplay.push( + + {categoryLayers} + , + ); + } + + /** + * TODO: For xs-s, the selector should be a popover modal + */ + + return ( + + + + {checkboxesToDisplay} + + + + ); +} diff --git a/src/map/MapPageComponent.jsx b/src/map/MapPageComponent.jsx new file mode 100644 index 0000000..a593ad2 --- /dev/null +++ b/src/map/MapPageComponent.jsx @@ -0,0 +1,18 @@ +import { Box } from '@mui/material'; +import React, { Suspense } from 'react'; + +const MapContainerComponent = React.lazy(() => import('./MapContainerComponent')); + +export default function MapPageComponent({ mapId, inputSelectedLayers }) { + return ( + + Loading...}> + + + + ); +} diff --git a/src/map/MapZoneSelectorComponent.jsx b/src/map/MapZoneSelectorComponent.jsx new file mode 100644 index 0000000..c6279ce --- /dev/null +++ b/src/map/MapZoneSelectorComponent.jsx @@ -0,0 +1,43 @@ +import { + Box, FormControlLabel, FormGroup, FormLabel, Radio, RadioGroup, useTheme, +} from '@mui/material'; +import React from 'react'; +import Scrollbars from 'react-custom-scrollbars-2'; + +export default function MapZoneSelectorComponent({ + currentZone, + handleZoneSelectorUpdate, +}) { + const theme = useTheme(); + return ( + + + + handleZoneSelectorUpdate(e.target.value)} + > + Occult Crescent + } label="South Horn" /> + Bozja + } label="Zadnor" /> + } label="The Bozjan Southern Front" /> + Eureka + } label="Eureka Hydatos" /> + } label="Eureka Pyros" /> + } label="Eureka Pagos" /> + } label="Eureka Anemos" /> + + + + + ); +} diff --git a/src/map/TooltipBaseComponent.css b/src/map/TooltipBaseComponent.css new file mode 100644 index 0000000..2d6fed2 --- /dev/null +++ b/src/map/TooltipBaseComponent.css @@ -0,0 +1,18 @@ +.tooltip-base-component { + width: 520px; + min-height: 50px; +} + +.tooltip-no-margin p { + margin: 0 !important; +} + +/* Stronger specificity to override .leaflet-popup-content p */ +.leaflet-popup-content .tooltip-no-margin p { + margin: 0 !important; +} + +/* Further increase specificity */ +.leaflet-popup-content :where(.tooltip-no-margin) p { + margin: 0 !important; +} \ No newline at end of file diff --git a/src/map/TooltipBaseComponent.jsx b/src/map/TooltipBaseComponent.jsx new file mode 100644 index 0000000..e628ed9 --- /dev/null +++ b/src/map/TooltipBaseComponent.jsx @@ -0,0 +1,55 @@ +import { + Box, + Divider, + Stack, + Typography, +} from '@mui/material'; +import React from 'react'; +import EurekaNMTooltipComponent from './tooltipcomponents/EurekaNMTooltipComponent'; +import AetheryteTooltipComponent from './tooltipcomponents/AetheryteTooltipComponent'; +import BozjaCETooltipComponent from './tooltipcomponents/BozjaCETooltipComponent'; + +export default function TooltipBaseComponent( + { + markerData, + icon, + type, + }, +) { + const renderContent = () => { + switch (type) { + case 'nms': + return ; + case 'aetherytes': + return ; + case 'criticalEngagements': + return ; + default: + return null; + } + }; + + return ( + + + + + {icon} + + + {markerData.popupTitle ?? markerData.name} + + + + + + {renderContent(markerData.type, markerData, icon)} + + + ); +} diff --git a/src/map/lib/poi/bsf.json b/src/map/lib/poi/bsf.json new file mode 100644 index 0000000..1ff0bde --- /dev/null +++ b/src/map/lib/poi/bsf.json @@ -0,0 +1,900 @@ +{ + "name": "The Bozjan Southern Front", + "categories": [ + { + "name": "General", + "enabled": true, + "layers": [ + { + "id": "namedLocations", + "name": "Named Locations", + "enabled": true + }, + { + "id": "aetherytes", + "name": "Aetherytes", + "enabled": true + }, + { + "id": "lostFindCaches", + "name": "Lost Find Caches", + "enabled": true + }, + { + "id": "traders", + "name": "Traders", + "enabled": true + }, + { + "id": "shops", + "name": "Shops", + "enabled": true + }, + { + "id": "repair", + "name": "Repair", + "enabled": true + } + ] + }, + { + "name": "Encounters", + "enabled": true, + "layers": [ + { + "id": "skirmishes", + "name": "Skirmishes", + "enabled": true + }, + { + "id": "criticalEngagements", + "name": "Critical Engagements", + "enabled": true + }, + { + "id": "duels", + "name": "Duels", + "enabled": true + } + ] + }, + { + "name": "Enemies", + "enabled": false, + "layers": [ + { + "id": "starMobs", + "name": "Star Mobs", + "enabled": false + }, + { + "id": "magitekMobs", + "name": "Magitek Mobs", + "enabled": false + }, + { + "id": "fragmentMobs", + "name": "Fragment Mobs", + "enabled": false + } + ] + }, + { + "name": "Progression", + "enabled": false, + "layers": [ + { + "id": "quests", + "name": "Quests", + "enabled": false + }, + { + "id": "fieldNotes", + "name": "Field Notes", + "enabled": false + } + ] + } + ], + "layers": [ + { + "id": "aetherytes" + }, + { + "id": "lostFindCaches" + }, + { + "id": "criticalEngagements" + } + ], + "parameters": { + "imageUrl": "bsf.png", + "bounds": { + "min": { + "lat": -1, + "lon": 1 + }, + "max": { + "lat": -42, + "lon": 42 + } + }, + "center": { + "lat": -21, + "lon": 21 + }, + "zoom": { + "default": 5, + "min": 3, + "max": 8, + "delta": 0.5, + "snap": 0.5, + "scrollPx": 200 + } + }, + "mapData": { + "namedLocations": { + "markerIcon": "poi-pin.png", + "waymarks": [ + { + "name": "Orphaned Ruins", + "@id": "bsf_orphanedruins", + "position": { + "x": 16, + "y": -17.7 + } + }, + { + "name": "Firelight's Coffin", + "@id": "bsf_firelightscoffin", + "position": { + "x": 25.2, + "y": -35.4 + } + }, + { + "name": "Castrum Lacus Litore", + "@id": "bsf_castrumlacuslitore", + "position": { + "x": 16.9, + "y": -9.4 + } + }, + { + "name": "The Alermuc Climb", + "@id": "bsf_thealermucclimb", + "position": { + "x": 19.9, + "y": -14.8 + } + }, + { + "name": "Old Bozja", + "@id": "bsf_oldbozja", + "position": { + "x": 20.7, + "y": -22.1 + } + }, + { + "name": "Southern Entrenchment", + "@id": "bsf_southernentrenchment", + "position": { + "x": 20.1, + "y": -28.2 + } + } + ] + }, + "lostFindCaches": { + "markerIcon": "lostfindscache.png", + "waymarks": [ + { + "name": "", + "popupTitle": "Lost Finds Cache", + "@id": "bsf_lostfindcache1", + "position": { + "x": 15.1, + "y": -30.2 + } + }, + { + "name": "", + "popupTitle": "Lost Finds Cache", + "@id": "bsf_lostfindcache2", + "position": { + "x": 28.9, + "y": -23.6 + } + }, + { + "name": "", + "popupTitle": "Lost Finds Cache", + "@id": "bsf_lostfindcache3", + "position": { + "x": 13.6, + "y": -23.8 + } + }, + { + "name": "", + "popupTitle": "Lost Finds Cache", + "@id": "bsf_lostfindcache4", + "position": { + "x": 22.1, + "y": -16.6 + } + } + ] + }, + "repair": { + "markerIcon": "repair.png", + "waymarks": [ + { + "name": "", + "@id": "bsf_repair1", + "position": { + "x": 14.6, + "y": -30.6 + } + } + ] + }, + "traders": { + "markerIcon": "trader.png", + "waymarks": [ + { + "name": "Resistance Quartermaster", + "@id": "bsf_trader01", + "position": { + "x": 14.2, + "y": -29.7 + } + }, + { + "name": "Resistance Historian", + "@id": "bsf_trader02", + "position": { + "x": 15.0, + "y": -29.1 + } + }, + { + "name": "Resistance Supplier", + "@id": "bsf_trader03", + "position": { + "x": 15.3, + "y": -29.9 + } + }, + { + "name": "Resistance Appraiser", + "@id": "bsf_trader04", + "position": { + "x": 15.2, + "y": -30.1 + } + }, + { + "name": "Resistance Appraiser", + "@id": "bsf_trader05", + "position": { + "x": 28.9, + "y": -23.6 + } + }, + { + "name": "Resistance Appraiser", + "@id": "bsf_trader06", + "position": { + "x": 13.8, + "y": -23.8 + } + }, + { + "name": "Resistance Appraiser", + "@id": "bsf_trader07", + "position": { + "x": 22.2, + "y": -16.6 + } + } + ] + }, + "shops": { + "markerIcon": "shop.png", + "waymarks": [ + { + "name": "Resistance Locksmith", + "@id": "bsf_shop01", + "position": { + "x": 15.1, + "y": -29.7 + } + } + ] + }, + "aetherytes": { + "markerIcon": "aetheryte.png", + "waymarks": [ + { + "name": "Utya's Aegis", + "@id": "bsf_utyasaegis", + "position": { + "x": 14.9, + "y": -29.9 + } + }, + { + "name": "Olana's Stand", + "@id": "bsf_olanastand", + "position": { + "x": 28.6, + "y": -23.6 + } + }, + { + "name": "Lunya's Stand", + "@id": "bsf_lunyasstand", + "position": { + "x": 13.7, + "y": -23.6 + } + }, + { + "name": "Camp Steva", + "@id": "bsf_campsteva", + "position": { + "x": 22.3, + "y": -16.8 + } + } + ] + }, + "skirmishes": { + "markerIcon": "fate-enemies.png", + "circle": { + "radius": 0.9, + "color": "#03c2fc" + }, + "waymarks": [ + { + "name": "All Pets Are Off", + "@id": "bsf_skirmish01", + "position": { + "x": 17, + "y": -26.8 + } + }, + { + "name": "Brought to Heal", + "@id": "bsf_skirmish02", + "position": { + "x": 28.6, + "y": -26.1 + } + }, + { + "name": "Can Carnivorous Plants Bloom Even on a Battlefield?", + "@id": "bsf_skirmish03", + "position": { + "x": 33.7, + "y": -29.5 + } + }, + { + "name": "Conflicting with the First Law", + "@id": "bsf_skirmish04", + "position": { + "x": 33.5, + "y": -29.3 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "More Machine Now than Man", + "@id": "bsf_skirmish05", + "position": { + "x": 27.9, + "y": -28.9 + } + }, + { + "name": "None of Them Knew They Were Robots", + "@id": "bsf_skirmish06", + "position": { + "x": 24.5, + "y": -27.8 + } + }, + { + "name": "Seeq and Destroy", + "@id": "bsf_skirmish07", + "position": { + "x": 28.8, + "y": -26.3 + } + }, + { + "name": "Sneak and Spell", + "@id": "bsf_skirmish08", + "position": { + "x": 20.2, + "y": -26.9 + } + }, + { + "name": "The Beasts Must Die", + "@id": "bsf_skirmish09", + "position": { + "x": 20.4, + "y": -27.1 + } + }, + { + "name": "Unrest for the Wicked", + "@id": "bsf_skirmish10", + "position": { + "x": 24.3, + "y": -27.6 + } + }, + { + "name": "Heavy Boots of Lead", + "@id": "bsf_skirmish11", + "position": { + "x": 30.6, + "y": -22 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "Help Wanted", + "@id": "bsf_skirmish12", + "position": { + "x": 18.2, + "y": -20.9 + }, + "iconOverride": "fate-defense.png" + }, + { + "name": "No Camping Allowed", + "@id": "bsf_skirmish13", + "position": { + "x": 17.8, + "y": -23.5 + } + }, + { + "name": "Parts and Recreation", + "@id": "bsf_skirmish14", + "position": { + "x": 25.4, + "y": -21.9 + }, + "iconOverride": "fate-gather.png" + }, + { + "name": "Pyromancer Supreme", + "@id": "bsf_skirmish15", + "position": { + "x": 18.2, + "y": -20.9 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "Red (Chocobo) Alert", + "@id": "bsf_skirmish16", + "position": { + "x": 27, + "y": -18.5 + } + }, + { + "name": "Scavengers of Man's Sorrow", + "@id": "bsf_skirmish17", + "position": { + "x": 25.2, + "y": -22.8 + } + }, + { + "name": "The Element of Supplies", + "@id": "bsf_skirmish18", + "position": { + "x": 17.6, + "y": -23.3 + } + }, + { + "name": "The Monster Mash", + "@id": "bsf_skirmish19", + "position": { + "x": 30.8, + "y": -22.2 + } + }, + { + "name": "Unicorn Flakes", + "@id": "bsf_skirmish20", + "position": { + "x": 31.6, + "y": -17.3 + }, + "iconOverride": "fate-defense.png" + }, + { + "name": "Demonstrably Demonic", + "@id": "bsf_skirmish21", + "position": { + "x": 11.3, + "y": -20.4 + } + }, + { + "name": "Desperately Seeking Something", + "@id": "bsf_skirmish22", + "position": { + "x": 24.5, + "y": -17.3 + } + }, + { + "name": "For Absent Friends", + "@id": "bsf_skirmish23", + "position": { + "x": 14.3, + "y": -18.2 + } + }, + { + "name": "I'm a Mechanical Man", + "@id": "bsf_skirmish24", + "position": { + "x": 20.8, + "y": -18 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "Let Slip the Dogs of War", + "@id": "bsf_skirmish25", + "position": { + "x": 14.1, + "y": -15.7 + } + }, + { + "name": "Murder Death Kill", + "@id": "bsf_skirmish26", + "position": { + "x": 14.3, + "y": -15.9 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "My Family and Other Animals", + "@id": "bsf_skirmish27", + "position": { + "x": 11.3, + "y": -15.2 + } + }, + { + "name": "Of Steel and Flame", + "@id": "bsf_skirmish28", + "position": { + "x": 14.5, + "y": -18.4 + }, + "iconOverride": "fate-boss.png" + }, + { + "name": "Supplies Party", + "@id": "bsf_skirmish29", + "position": { + "x": 20.9, + "y": -14.7 + }, + "iconOverride": "fate-gather.png" + }, + { + "name": "The War Against the Machines", + "@id": "bsf_skirmish30", + "position": { + "x": 11.5, + "y": -20.6 + } + }, + { + "name": "The Wild Bunch", + "@id": "bsf_skirmish31", + "position": { + "x": 21.1, + "y": -14.9 + } + }, + { + "name": "Waste the Rainbow", + "@id": "bsf_skirmish32", + "position": { + "x": 24.7, + "y": -17.5 + }, + "iconOverride": "fate-boss.png" + } + ] + }, + "criticalEngagements": { + "markerIcon": "fate-nm.png", + "circle": { + "radius": 0.9, + "color": "#e0635a" + }, + "waymarks": [ + { + "name": "Kill It with Fire", + "@id": "bsf_ce01", + "position": { + "x": 17.2, + "y": -27 + }, + "metadata": { + "boss": "Peerifool", + "spawnedBy": { + "type": "skirmish", + "name": "All Pets Are Off" + }, + "rewards": [ + { + "name": "Field Notes on Clarricie", + "type": "fieldNote" + }, + { + "name": "Garlean Synthetic Fabric", + "type": "garleanFabric" + } + ] + } + }, + { + "name": "The Baying of the Hound(s)", + "@id": "bsf_ce02", + "position": { + "x": 22, + "y": -29 + }, + "metadata": { + "boss": "Canus Dirus", + "spawnedBy": { + "type": "mob", + "name": "4th Legion Death Claw" + } + } + }, + { + "name": "The Shadow of Death's Hand", + "@id": "bsf_ce03", + "position": { + "x": 35.4, + "y": -26.2 + }, + "metadata": { + "boss": "Akbaba", + "spawnedBy": { + "type": "mob", + "name": "4th Legion Roader" + }, + "rewards": [ + { + "name": "Field Notes on Xeven", + "type": "fieldNote" + } + ] + } + }, + { + "name": "Vigil for the Lost", + "@id": "bsf_ce04", + "position": { + "x": 27.9, + "y": -30 + }, + "metadata": { + "boss": "Vigilia", + "spawnedBy": { + "type": "skirmish", + "name": "More Machine Now than Man" + } + } + }, + { + "name": "Patriot Games", + "@id": "bsf_ce05", + "position": { + "x": 14.2, + "y": -21.3 + }, + "metadata": { + "boss": "Patriot", + "spawnedBy": { + "type": "skirmish", + "name": "The Fires of War" + } + } + }, + { + "name": "The Final Furlong", + "@id": "bsf_ce06", + "position": { + "x": 31.9, + "y": -17.6 + }, + "metadata": { + "boss": "Spartoi", + "spawnedBy": { + "type": "skirmish", + "name": "Unicorn Flakes" + }, + "rewards": [ + { + "name": "Field Notes on Llofii", + "type": "fieldNote" + } + ] + } + }, + { + "name": "The Fires of War", + "@id": "bsf_ce07", + "position": { + "x": 20.6, + "y": -24.3 + }, + "iconOverride": "fate-wave.png", + "metadata": { + "boss": "Pyrobolus Mater", + "spawnedBy": { + "type": "mob", + "name": "4th Legion Gunship" + } + } + }, + { + "name": "The Hunt for Red Choctober", + "@id": "bsf_ce08", + "position": { + "x": 26.8, + "y": -18.4 + }, + "metadata": { + "boss": "Red Comet", + "spawnedBy": { + "type": "skirmish", + "name": "Red (Chocobo) Alert" + } + } + }, + { + "name": "Metal Fox Chaos", + "@id": "bsf_ce09", + "position": { + "x": 14.3, + "y": -18.3 + }, + "metadata": { + "boss": "Dáinsleif", + "spawnedBy": { + "type": "skirmish", + "name": "Of Steel and Flame" + }, + "rewards": [ + { + "name": "10x Forgotten Fragment of Resolve", + "type": "bsfFragment" + } + ] + } + }, + { + "name": "Rise of the Robots", + "@id": "bsf_ce10", + "position": { + "x": 21, + "y": -17.8 + }, + "metadata": { + "boss": "Mark XIII-X Magitek Laborer", + "spawnedBy": { + "type": "skirmish", + "name": "I'm a Mechanical Man" + }, + "rewards": [ + { + "name": "Field Notes on Sicinius", + "type": "fieldNote" + } + ] + } + }, + { + "name": "Trampled under Hoof", + "@id": "bsf_ce11", + "position": { + "x": 9.9, + "y": -18.3 + }, + "metadata": { + "boss": "Eale", + "spawnedBy": { + "type": "mob", + "name": "4th Legion Armored Weapon" + }, + "rewards": [ + { + "name": "10x Forgotten Fragment of Resolve", + "type": "bsfFragment" + } + ] + } + }, + { + "name": "Where Strode the Behemoth", + "@id": "bsf_ce12", + "position": { + "x": 23.6, + "y": -14.9 + }, + "metadata": { + "boss": "Chlevnik", + "spawnedBy": { + "type": "skirmish", + "name": "Trampled under Hoof" + }, + "rewards": [ + { + "name": "10x Forgotten Fragment of Resolve", + "type": "bsfFragment" + } + ] + } + } + ] + }, + "duels": { + "markerIcon": "fate-duel.png", + "circle": { + "radius": 0.5, + "color": "#e0635a" + }, + "waymarks": [ + { + "name": "Aces High", + "@id": "bsf_duel1", + "position": { + "x": 31.6, + "y": -26.8 + } + }, + { + "name": "Beast of Man", + "@id": "bsf_duel2", + "position": { + "x": 23.2, + "y": -20.6 + } + }, + { + "name": "And the Flames Went Higher", + "@id": "bsf_duel3", + "position": { + "x": 18.7, + "y": -15.9 + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/map/lib/poi/hydatos.json b/src/map/lib/poi/hydatos.json new file mode 100644 index 0000000..183dea4 --- /dev/null +++ b/src/map/lib/poi/hydatos.json @@ -0,0 +1,1654 @@ +{ + "name": "Eureka Hydatos", + "id": "hydatos", + "region": "Eureka", + "categories": [ + { + "name": "General", + "enabled": true, + "layers": [ + { + "id": "namedLocations", + "name": "Named Locations", + "enabled": true + }, + { + "id": "aetherytes", + "name": "Aetherytes", + "enabled": true + }, + { + "id": "elementals", + "name": "Elementals", + "enabled": true + }, + { + "id": "logosManipulators", + "name": "Logos Manipulators", + "enabled": true + }, + { + "id": "magiaMelders", + "name": "Magia Melders", + "enabled": true + }, + { + "id": "traders", + "name": "Traders", + "enabled": true + }, + { + "id": "shops", + "name": "Shops", + "enabled": true + }, + { + "id": "repair", + "name": "Repair", + "enabled": true + } + ] + }, + { + "name": "Encounters", + "enabled": true, + "layers": [ + { + "id": "nms", + "name": "NMs", + "enabled": true + }, + { + "id": "bunnyCoffers", + "name": "Bunny Coffers", + "enabled": true + }, + { + "id": "baPortals", + "name": "BA Portals", + "enabled": true + } + ] + }, + { + "name": "Enemies", + "enabled": false, + "layers": [ + { + "id": "mobs", + "name": "Mobs", + "enabled": false + }, + { + "id": "nmPrepMobs", + "name": "NM Prep Mobs", + "enabled": false + }, + { + "id": "sprites", + "name": "Sprites", + "enabled": false + } + ] + }, + { + "name": "Progression", + "enabled": false, + "layers": [ + { + "id": "quests", + "name": "Quests", + "enabled": false + } + ] + } + ], + "layers": [ + { + "id": "namedLocations" + }, + { + "id": "aetherytes" + }, + { + "id": "nms" + } + ], + "parameters": { + "imageUrl": "hydatos.png", + "bounds": { + "min": { + "lat": -1, + "lon": 1 + }, + "max": { + "lat": -42, + "lon": 42 + } + }, + "center": { + "lat": -21, + "lon": 21 + }, + "zoom": { + "default": 5, + "min": 3, + "max": 8, + "delta": 0.5, + "snap": 0.5, + "scrollPx": 200 + } + }, + "mapData": { + "namedLocations": { + "markerIcon": "poi-pin.png", + "waymarks": [ + { + "name": "The Aetherbridge Foundation", + "@id": "hyd_aetherbridgefoundation", + "position": { + "x": 24.0, + "y": -31.0 + } + }, + { + "name": "The Western Columns", + "@id": "hyd_westerncolumns", + "position": { + "x": 10.7, + "y": -29.7 + } + }, + { + "name": "The Central Columns", + "@id": "hyd_centralcolumns", + "position": { + "x": 20.3, + "y": -24.9 + } + }, + { + "name": "The Eastern Columns", + "@id": "hyd_easterncolumns", + "position": { + "x": 31.2, + "y": -27.3 + } + }, + { + "name": "The Crystal Dragon's Bloom", + "@id": "hyd_crystaldragonsbloom", + "position": { + "x": 32.8, + "y": -19.0 + } + } + ] + }, + "aetherytes": { + "markerIcon": "aetheryte.png", + "waymarks": [ + { + "name": "Central Point", + "@id": "hyd_centralpoint", + "position": { + "x": 20.4, + "y": -13.6 + }, + "metadata": { + "unlock": 50 + } + }, + { + "name": "Unverified Research", + "@id": "hyd_unverifiedresearch", + "position": { + "x": 9.9, + "y": -28.0 + }, + "metadata": { + "unlock": 51 + } + }, + { + "name": "The Dormitory", + "@id": "hyd_dormitory", + "position": { + "x": 37.0, + "y": -22.6 + }, + "metadata": { + "unlock": 55 + } + } + ] + }, + "elementals": { + "markerIcon": "elemental.png", + "waymarks": [ + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental01", + "position": { + "x": 5.1, + "y": -16.1 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental02", + "position": { + "x": 10.0, + "y": -14.3 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental03", + "position": { + "x": 16.0, + "y": -13.3 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental04", + "position": { + "x": 14.6, + "y": -16.5 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental05", + "position": { + "x": 13.0, + "y": -17.8 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental06", + "position": { + "x": 7.8, + "y": -19.6 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental07", + "position": { + "x": 4.4, + "y": -23.9 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental08", + "position": { + "x": 7.1, + "y": -23.9 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental09", + "position": { + "x": 5.5, + "y": -30.0 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental10", + "position": { + "x": 9.2, + "y": -29.7 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental11", + "position": { + "x": 9.8, + "y": -27.0 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental12", + "position": { + "x": 14.2, + "y": -29.6 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental13", + "position": { + "x": 18.2, + "y": -20.4 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental14", + "position": { + "x": 19.2, + "y": -24.3 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental15", + "position": { + "x": 22.1, + "y": -30.1 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental16", + "position": { + "x": 23.7, + "y": -27.1 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental17", + "position": { + "x": 28.6, + "y": -21.1 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental18", + "position": { + "x": 30.8, + "y": -26.1 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental19", + "position": { + "x": 29.5, + "y": -30.3 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental20", + "position": { + "x": 34.2, + "y": -16.7 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental21", + "position": { + "x": 38.2, + "y": -17.2 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental22", + "position": { + "x": 33.9, + "y": -21.6 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental23", + "position": { + "x": 37.9, + "y": -22.9 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental24", + "position": { + "x": 35.6, + "y": -26.6 + } + }, + { + "name": "", + "popupTitle": "Elemental Spawn Location", + "@id": "hyd_elemental25", + "position": { + "x": 36.9, + "y": -29.7 + } + } + ] + }, + "logosManipulators": { + "markerIcon": "logos-manipulator.png", + "waymarks": [ + { + "name": "Logos Manipulator", + "@id": "hyd_logosmanipulator1", + "position": { + "x": 21.4, + "y": -13.5 + } + } + ] + }, + "magiaMelders": { + "markerIcon": "magia-melder.png", + "waymarks": [ + { + "name": "Magia Melder", + "@id": "hyd_magiamelder1", + "position": { + "x": 19.7, + "y": -13.8 + } + } + ] + }, + "traders": { + "markerIcon": "trader.png", + "waymarks": [ + { + "name": "Trader", + "@id": "hyd_trader1", + "position": { + "x": 20.5, + "y": -13.3 + } + } + ] + }, + "shops": { + "markerIcon": "shop.png", + "waymarks": [ + { + "name": "Expedition Engineer", + "@id": "hyd_shop1", + "position": { + "x": 19.7, + "y": -13.2 + } + }, + { + "name": "Shop", + "@id": "hyd_shop2", + "position": { + "x": 19.8, + "y": -14.0 + } + }, + { + "name": "Shop", + "@id": "hyd_shop3", + "position": { + "x": 20.0, + "y": -14.1 + } + }, + { + "name": "Expedition Alchemist", + "@id": "hyd_shop4", + "position": { + "x": 20.9, + "y": -13.3 + } + }, + { + "name": "Drake", + "@id": "hyd_shop5", + "position": { + "x": 21.3, + "y": -13.3 + } + }, + { + "name": "Eureka Weapons & Gear", + "@id": "hyd_shop1", + "position": { + "x": 21.4, + "y": -13.7 + } + } + ] + }, + "repair": { + "markerIcon": "repair.png", + "waymarks": [ + { + "name": "Repair", + "@id": "hyd_repair1", + "position": { + "x": 19.7, + "y": -13.5 + } + } + ] + }, + "baPortals": { + "markerIcon": "baportal.png", + "waymarks": [ + { + "name": "1-1", + "@id": "ba-1-1", + "position": { + "x": 4.2, + "y": -15.1 + } + }, + { + "name": "1-2", + "@id": "ba-1-2", + "position": { + "x": 7.2, + "y": -14.9 + } + }, + { + "name": "1-3", + "@id": "ba-1-3", + "position": { + "x": 10.6, + "y": -14.6 + } + }, + { + "name": "1-4", + "@id": "ba-1-4", + "position": { + "x": 6.9, + "y": -18.7 + } + }, + { + "name": "1-5", + "@id": "ba-1-5", + "position": { + "x": 10.1, + "y": -17.8 + } + }, + { + "name": "1-6", + "@id": "ba-1-6", + "position": { + "x": 6.2, + "y": -21.8 + } + }, + { + "name": "1-7", + "@id": "ba-1-7", + "position": { + "x": 4.3, + "y": -26.1 + } + }, + { + "name": "1-8", + "@id": "ba-1-8", + "position": { + "x": 7.2, + "y": -29.3 + } + }, + { + "name": "2-1", + "@id": "ba-2-1", + "position": { + "x": 15.9, + "y": -14.6 + } + }, + { + "name": "2-2", + "@id": "ba-2-2", + "position": { + "x": 16.4, + "y": -18.7 + } + }, + { + "name": "2-3", + "@id": "ba-2-3", + "position": { + "x": 10.7, + "y": -21.9 + } + }, + { + "name": "2-4", + "@id": "ba-2-4", + "position": { + "x": 15.9, + "y": -22.2 + } + }, + { + "name": "2-5", + "@id": "ba-2-5", + "position": { + "x": 13.7, + "y": -24.3 + } + }, + { + "name": "2-6", + "@id": "ba-2-6", + "position": { + "x": 10.6, + "y": -25.8 + } + }, + { + "name": "2-7", + "@id": "ba-2-7", + "position": { + "x": 14.8, + "y": -26.8 + } + }, + { + "name": "2-8", + "@id": "ba-2-8", + "position": { + "x": 16.7, + "y": -29.2 + } + }, + { + "name": "3-1", + "@id": "ba-3-1", + "position": { + "x": 21.2, + "y": -17.2 + } + }, + { + "name": "3-2", + "@id": "ba-3-2", + "position": { + "x": 19.4, + "y": -20.1 + } + }, + { + "name": "3-3", + "@id": "ba-3-3", + "position": { + "x": 23.8, + "y": -21.9 + } + }, + { + "name": "3-4", + "@id": "ba-3-4", + "position": { + "x": 19.2, + "y": -26.8 + } + }, + { + "name": "3-5", + "@id": "ba-3-5", + "position": { + "x": 23.0, + "y": -27.0 + } + }, + { + "name": "3-6", + "@id": "ba-3-6", + "position": { + "x": 19.2, + "y": -28.6 + } + }, + { + "name": "3-7", + "@id": "ba-3-7", + "position": { + "x": 20.8, + "y": -29.0 + } + }, + { + "name": "3-8", + "@id": "ba-3-8", + "position": { + "x": 22.9, + "y": -29.1 + } + }, + { + "name": "4-1", + "@id": "ba-4-1", + "position": { + "x": 25.0, + "y": -16.4 + } + }, + { + "name": "4-2", + "@id": "ba-4-2", + "position": { + "x": 26.6, + "y": -19.1 + } + }, + { + "name": "4-3", + "@id": "ba-4-3", + "position": { + "x": 28.7, + "y": -23.4 + } + }, + { + "name": "4-4", + "@id": "ba-4-4", + "position": { + "x": 25.2, + "y": -25.3 + } + }, + { + "name": "4-5", + "@id": "ba-4-5", + "position": { + "x": 26.9, + "y": -26.7 + } + }, + { + "name": "4-6", + "@id": "ba-4-6", + "position": { + "x": 26.0, + "y": -27.9 + } + }, + { + "name": "4-7", + "@id": "ba-4-7", + "position": { + "x": 25.4, + "y": -28.9 + } + }, + { + "name": "4-8", + "@id": "ba-4-8", + "position": { + "x": 25.7, + "y": -30.1 + } + }, + { + "name": "5-1", + "@id": "ba-5-1", + "position": { + "x": 28.9, + "y": -15.3 + } + }, + { + "name": "5-2", + "@id": "ba-5-2", + "position": { + "x": 33.3, + "y": -17.0 + } + }, + { + "name": "5-3", + "@id": "ba-5-3", + "position": { + "x": 29.9, + "y": -19.6 + } + }, + { + "name": "5-4", + "@id": "ba-5-4", + "position": { + "x": 32.3, + "y": -24.8 + } + }, + { + "name": "5-5", + "@id": "ba-5-5", + "position": { + "x": 29.6, + "y": -26.3 + } + }, + { + "name": "5-6", + "@id": "ba-5-6", + "position": { + "x": 30.8, + "y": -28.6 + } + }, + { + "name": "5-7", + "@id": "ba-5-7", + "position": { + "x": 30.3, + "y": -30.1 + } + }, + { + "name": "5-8", + "@id": "ba-5-8", + "position": { + "x": 31.7, + "y": -29.9 + } + }, + { + "name": "6-1", + "@id": "ba-6-1", + "position": { + "x": 35.2, + "y": -13.9 + } + }, + { + "name": "6-2", + "@id": "ba-6-2", + "position": { + "x": 37.9, + "y": -15.0 + } + }, + { + "name": "6-3", + "@id": "ba-6-3", + "position": { + "x": 36.0, + "y": -19.0 + } + }, + { + "name": "6-4", + "@id": "ba-6-4", + "position": { + "x": 37.3, + "y": -23.7 + } + }, + { + "name": "6-5", + "@id": "ba-6-5", + "position": { + "x": 33.0, + "y": -27.8 + } + }, + { + "name": "6-6", + "@id": "ba-6-6", + "position": { + "x": 37.2, + "y": -27.9 + } + }, + { + "name": "6-7", + "@id": "ba-6-7", + "position": { + "x": 32.7, + "y": -29.0 + } + }, + { + "name": "6-8", + "@id": "ba-6-8", + "position": { + "x": 35.8, + "y": -29.9 + } + } + ], + "annotations": [ + { + "@id": "ba-line-12", + "type": "polyline", + "path": [ + { + "x": 11.0, + "y": -14.0 + }, + { + "x": 11.0, + "y": -19.0 + }, + { + "x": 9.0, + "y": -21.5 + }, + { + "x": 9.0, + "y": -30 + } + ] + }, + { + "@id": "ba-line-23", + "type": "polyline", + "path": [ + { + "x": 17.8, + "y": -12.5 + }, + { + "x": 17.8, + "y": -30.1 + } + ] + }, + { + "@id": "ba-line-34", + "type": "polyline", + "path": [ + { + "x": 24.1, + "y": -14.8 + }, + { + "x": 24.1, + "y": -31.2 + } + ] + }, + { + "@id": "ba-line-45", + "type": "polyline", + "path": [ + { + "x": 28.0, + "y": -14.6 + }, + { + "x": 28.0, + "y": -17.0 + }, + { + "x": 29.0, + "y": -19.0 + }, + { + "x": 29.0, + "y": -30.7 + } + ] + }, + { + "@id": "ba-line-56", + "type": "polyline", + "path": [ + { + "x": 34.0, + "y": -13.2 + }, + { + "x": 34.0, + "y": -25.0 + }, + { + "x": 32.3, + "y": -26.5 + }, + { + "x": 32.3, + "y": -30.6 + } + ] + }, + { + "@id": "ba-1-header", + "type": "largeText", + "text": "1", + "position": { + "x": 7.0, + "y": -8.0 + } + }, + { + "@id": "ba-2-header", + "type": "largeText", + "text": "2", + "position": { + "x": 14.0, + "y": -8.0 + } + }, + { + "@id": "ba-3-header", + "type": "largeText", + "text": "3", + "position": { + "x": 20.5, + "y": -8.0 + } + }, + { + "@id": "ba-4-header", + "type": "largeText", + "text": "4", + "position": { + "x": 25.5, + "y": -8.0 + } + }, + { + "@id": "ba-5-header", + "type": "largeText", + "text": "5", + "position": { + "x": 31.0, + "y": -8.0 + } + }, + { + "@id": "ba-6-header", + "type": "largeText", + "text": "6", + "position": { + "x": 36.5, + "y": -8.0 + } + } + ] + }, + "bunnyCoffers": { + "markerIcon": "coffer.png", + "waymarks": [ + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer01", + "position": { + "x": 5.4, + "y": -12.2 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer02", + "position": { + "x": 9.4, + "y": -13.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer03", + "position": { + "x": 3.0, + "y": -16.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer04", + "position": { + "x": 8.4, + "y": -19.4 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer05", + "position": { + "x": 4.1, + "y": -22.1 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer06", + "position": { + "x": 7.8, + "y": -23.6 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer07", + "position": { + "x": 3.1, + "y": -27.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer08", + "position": { + "x": 5.5, + "y": -28.6 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer09", + "position": { + "x": 10.2, + "y": -30.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer10", + "position": { + "x": 14.4, + "y": -28.7 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer11", + "position": { + "x": 18.1, + "y": -30.0 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer12", + "position": { + "x": 17.7, + "y": -19.1 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer13", + "position": { + "x": 12.7, + "y": -17.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer14", + "position": { + "x": 15.1, + "y": -16.4 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer15", + "position": { + "x": 19.1, + "y": -13.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer16", + "position": { + "x": 23.9, + "y": -18.7 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer17", + "position": { + "x": 21.6, + "y": -23.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer18", + "position": { + "x": 24.7, + "y": -24.0 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer19", + "position": { + "x": 24.2, + "y": -31.2 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer20", + "position": { + "x": 26.1, + "y": -13.3 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer21", + "position": { + "x": 27.2, + "y": -20.6 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer22", + "position": { + "x": 28.9, + "y": -22.9 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer23", + "position": { + "x": 28.3, + "y": -26.6 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer24", + "position": { + "x": 30.8, + "y": -16.8 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer25", + "position": { + "x": 38.4, + "y": -13.3 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer26", + "position": { + "x": 34.6, + "y": -16.4 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer27", + "position": { + "x": 38.2, + "y": -20.5 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer28", + "position": { + "x": 34.8, + "y": -23.9 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer29", + "position": { + "x": 38.9, + "y": -26.1 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer30", + "position": { + "x": 38.4, + "y": -30.7 + } + }, + { + "name": "", + "popupTitle": "Bunny Coffer Spawn Location", + "@id": "hydatoscoffer31", + "position": { + "x": 33.1, + "y": -29.3 + } + } + ] + }, + "nms": { + "markerIcon": "fate-nm.png", + "circle": { + "radius": 0.9, + "color": "#03c2fc" + }, + "waymarks": [ + { + "name": "Lv50 Khalamari", + "popupTitle": "I Ink, Therefore I Am", + "@id": "hyd_nm1", + "position": { + "x": 10.8, + "y": -25.6 + }, + "metadata": { + "boss": "Khalamari", + "level": 50, + "element": "Water", + "spawnedBy": { + "name": "Xzomit", + "element": "Water", + "level": 55 + } + } + }, + { + "name": "Bunny", + "popupTitle": "Drink Me", + "@id": "hyd_nmbunny", + "position": { + "x": 13.8, + "y": -21.6 + }, + "metadata": { + "boss": "Bunny FATE", + "level": 50, + "element": "Water" + } + }, + { + "name": "Lv51 Stegodon", + "popupTitle": "From Tusk till Dawn", + "@id": "hyd_nm2", + "position": { + "x": 10.4, + "y": -17.2 + }, + "metadata": { + "boss": "Stegodon", + "level": 51, + "element": "Earth", + "spawnedBy": { + "name": "Hydatos Primelephas", + "element": "Earth", + "level": 56 + } + } + }, + { + "name": "Lv52 Molech", + "popupTitle": "Bullheaded Berserker", + "@id": "hyd_nm3", + "position": { + "x": 8.1, + "y": -21.8 + }, + "metadata": { + "boss": "Molech", + "level": 52, + "element": "Ice", + "spawnedBy": { + "name": "Val Nullchu", + "element": "Earth", + "level": 57 + } + } + }, + { + "name": "Lv 53 Piasa", + "popupTitle": "Mad, Bad, and Fabulous to Know", + "@id": "hyd_nm4", + "position": { + "x": 7.1, + "y": -14.5 + }, + "metadata": { + "boss": "Piasa", + "level": 53, + "element": "Wind", + "spawnedBy": { + "name": "Vivid Gastornis", + "element": "Wind", + "level": 58 + } + } + }, + { + "name": "Lv54 Frostmane", + "popupTitle": "Fearful Symmetry", + "@id": "hyd_nm5", + "position": { + "x": 8.2, + "y": -26.1 + }, + "metadata": { + "boss": "Frostmane", + "level": 54, + "element": "Fire", + "spawnedBy": { + "name": "Northern Tiger", + "element": "Earth", + "level": 59 + } + } + }, + { + "name": "Lv55 Daphne", + "popupTitle": "Crawling Chaos", + "@id": "hyd_nm6", + "position": { + "x": 24.2, + "y": -19.0 + }, + "metadata": { + "boss": "Daphne", + "level": 55, + "element": "Water", + "spawnedBy": { + "name": "Dark Void Monk", + "element": "Water", + "level": 60 + } + } + }, + { + "name": "Lv56 King Goldemar", + "popupTitle": "Duty-free", + "@id": "hyd_nm7", + "position": { + "x": 29.1, + "y": -23.0 + }, + "metadata": { + "boss": "King Goldemar", + "level": 56, + "element": "Lightning", + "spawnedBy": { + "name": "Hydatos Wraith", + "element": "Fire", + "level": 61, + "spawnCondition": { + "time": "Night" + } + } + } + }, + { + "name": "Lv57 Leuke", + "popupTitle": "Leukewarm Reception", + "@id": "hyd_nm8", + "position": { + "x": 37.4, + "y": -26.4 + }, + "metadata": { + "boss": "Leuke", + "level": 57, + "element": "Earth", + "spawnedBy": { + "name": "Tigerhawk", + "element": "Wind", + "level": 62 + } + } + }, + { + "name": "Lv58 Barong", + "popupTitle": "Robber Barong", + "@id": "hyd_nm9", + "position": { + "x": 32.2, + "y": -25.3 + }, + "metadata": { + "boss": "Barong", + "level": 58, + "element": "Fire", + "spawnedBy": { + "name": "Laboratory Lion", + "element": "Earth", + "level": 63 + } + } + }, + { + "name": "Lv59 Ceto", + "popupTitle": "Stone-cold Killer", + "@id": "hyd_nm10", + "position": { + "x": 36.3, + "y": -14.0 + }, + "metadata": { + "boss": "Ceto", + "level": 59, + "element": "Water", + "spawnedBy": { + "name": "Hydatos Delphine", + "element": "Fire", + "level": 64 + } + } + }, + { + "name": "Lv60 Provenance Watcher", + "popupTitle": "Crystalline Provenance", + "@id": "hyd_nm11", + "position": { + "x": 32.8, + "y": -19.6 + }, + "metadata": { + "boss": "Provenance Watcher", + "level": 60, + "element": "Fire", + "spawnedBy": { + "name": "Crystal Claw", + "element": "Fire", + "level": 65 + } + } + }, + { + "name": "Ovni", + "popupTitle": "I Don't Want to Believe", + "@id": "hyd_nm12", + "position": { + "x": 26.3, + "y": -29.2 + }, + "metadata": { + "boss": "Ovni", + "level": 60, + "element": "Ice", + "spawnCondition": { + "weather": "Umbral Turbulence" + } + } + }, + { + "name": "Support", + "popupTitle": "The Baldesion Arsenal: Expedition Support", + "@id": "hyd_nm13", + "position": { + "x": 18.7, + "y": -28.4 + }, + "metadata": { + "boss": "Tristitia", + "level": 60, + "element": "Wind", + "spawnCondition": { + "duty": "The Baldesion Arsenal" + } + } + } + ] + } + } +} \ No newline at end of file diff --git a/src/map/tooltipcomponents/AetheryteTooltipComponent.jsx b/src/map/tooltipcomponents/AetheryteTooltipComponent.jsx new file mode 100644 index 0000000..fd68288 --- /dev/null +++ b/src/map/tooltipcomponents/AetheryteTooltipComponent.jsx @@ -0,0 +1,15 @@ +import { Stack, Typography } from '@mui/material'; +import React from 'react'; + +export default function AetheryteTooltipComponent({ markerData }) { + if (markerData.metadata?.unlock) { + return ( + + Unlocks at + {`Level ${markerData.metadata.unlock}`} + + ); + } + + return null; +} diff --git a/src/map/tooltipcomponents/BozjaCETooltipComponent.jsx b/src/map/tooltipcomponents/BozjaCETooltipComponent.jsx new file mode 100644 index 0000000..8e48206 --- /dev/null +++ b/src/map/tooltipcomponents/BozjaCETooltipComponent.jsx @@ -0,0 +1,54 @@ +import { Box, Stack, Typography } from '@mui/material'; +import React from 'react'; + +export default function BozjaCETooltipComponent({ markerData }) { + const renderSpawnedBy = () => { + if (markerData.metadata.spawnedBy) { + return ( + + + {markerData.metadata.spawnedBy.type} + + {markerData.metadata.spawnedBy.name} + + ); + } + return null; + }; + + const renderRewards = () => { + if (markerData.metadata.rewards) { + return markerData.metadata.rewards.map((reward) => ( + + + {reward.type} + + {reward.name} + + )); + } + return null; + }; + + return ( + + Critical Engagement + Boss + {markerData.metadata.boss} + {markerData.metadata.spawnedBy ? Spawned by : null} + {renderSpawnedBy()} + {markerData.metadata.rewards ? Rewards : null} + {renderRewards()} + + ); +} diff --git a/src/map/tooltipcomponents/EurekaNMTooltipComponent.jsx b/src/map/tooltipcomponents/EurekaNMTooltipComponent.jsx new file mode 100644 index 0000000..029b97d --- /dev/null +++ b/src/map/tooltipcomponents/EurekaNMTooltipComponent.jsx @@ -0,0 +1,42 @@ +import { Box, Stack, Typography } from '@mui/material'; +import React from 'react'; + +export default function EurekaNMTooltipComponent({ markerData }) { + const renderSpawnedBy = () => { + if (markerData.metadata.spawnedBy) { + return ( + + + {markerData.name} + + {`Lv${markerData.metadata.spawnedBy.level} ${markerData.metadata.spawnedBy.name}`} + + ); + } + return null; + }; + + return ( + + Notorious Monster + + + {markerData.name} + + {markerData.name} + + {markerData.metadata.spawnedBy ? Spawned by : null} + {renderSpawnedBy()} + + ); +}