From 8d0764d0fa88d36865f1fc412356c4ff2bc8a26d Mon Sep 17 00:00:00 2001 From: Patric Stout Date: Sun, 12 May 2024 11:54:50 +0200 Subject: [PATCH] feat: show launcher/turret slots and usage above fit (#112) --- src/EveDataProvider/EveDataProvider.tsx | 14 +++- src/HardwareListing/HardwareListing.tsx | 10 +-- src/Icon/Icon.tsx | 2 + src/ShipFit/ShipFit.module.css | 23 +++++++ src/ShipFit/ShipFit.tsx | 67 ++++++++++++++++++- src/ShipFitExtended/ShipFitExtended.tsx | 2 +- .../ShipSnapshotProvider.tsx | 14 ++++ 7 files changed, 120 insertions(+), 12 deletions(-) diff --git a/src/EveDataProvider/EveDataProvider.tsx b/src/EveDataProvider/EveDataProvider.tsx index d5de575..08c7d9d 100644 --- a/src/EveDataProvider/EveDataProvider.tsx +++ b/src/EveDataProvider/EveDataProvider.tsx @@ -16,6 +16,7 @@ interface DogmaData { typeDogma?: Record; dogmaEffects?: Record; dogmaAttributes?: Record; + effectMapping?: Record; attributeMapping?: Record; } @@ -44,6 +45,7 @@ function isLoaded(dogmaData: DogmaData): boolean | undefined { if (dogmaData.typeDogma === undefined) return undefined; if (dogmaData.dogmaEffects === undefined) return undefined; if (dogmaData.dogmaAttributes === undefined) return undefined; + if (dogmaData.effectMapping === undefined) return undefined; if (dogmaData.attributeMapping === undefined) return undefined; return true; @@ -89,25 +91,31 @@ export const EveDataProvider = (props: DogmaDataProps) => { }, [dataUrl]); React.useEffect(() => { - if (!dogmaData.dogmaAttributes) return; + if (!dogmaData.dogmaAttributes || !dogmaData.dogmaEffects) return; - /* Create a reverse mapping to quickly lookup attribute name to attribute ID. */ + /* Create a reverse mapping to quickly lookup attribute/effect name to attribute/effect ID. */ const attributeMapping: Record = {}; for (const id in dogmaData.dogmaAttributes) { const name = dogmaData.dogmaAttributes[id].name; attributeMapping[name] = parseInt(id); } + const effectMapping: Record = {}; + for (const id in dogmaData.dogmaEffects) { + const name = dogmaData.dogmaEffects[id].name; + effectMapping[name] = parseInt(id); + } setDogmaData((prevDogmaData: DogmaData) => { const newDogmaData = { ...prevDogmaData, attributeMapping: attributeMapping, + effectMapping: effectMapping, }; newDogmaData.loaded = isLoaded(newDogmaData); return newDogmaData; }); - }, [dogmaData.dogmaAttributes]); + }, [dogmaData.dogmaAttributes, dogmaData.dogmaEffects]); return {props.children}; }; diff --git a/src/HardwareListing/HardwareListing.tsx b/src/HardwareListing/HardwareListing.tsx index 8333334..b85166e 100644 --- a/src/HardwareListing/HardwareListing.tsx +++ b/src/HardwareListing/HardwareListing.tsx @@ -207,15 +207,15 @@ export const HardwareListing = () => { slotType = eveData.typeDogma?.[typeId]?.dogmaEffects .map((effect) => { switch (effect.effectID) { - case 11: + case eveData.effectMapping?.loPower: return "lowslot"; - case 13: + case eveData.effectMapping?.medPower: return "medslot"; - case 12: + case eveData.effectMapping?.hiPower: return "hislot"; - case 2663: + case eveData.effectMapping?.rigSlot: return "rig"; - case 3772: + case eveData.effectMapping?.subSystem: return "subsystem"; } }) diff --git a/src/Icon/Icon.tsx b/src/Icon/Icon.tsx index 7e9fbfb..0a05fb1 100644 --- a/src/Icon/Icon.tsx +++ b/src/Icon/Icon.tsx @@ -22,6 +22,8 @@ const iconMapping = { "fitting-lowslot": "texture/classes/fitting/filtericonlowslot.png", "fitting-medslot": "texture/classes/fitting/filtericonmediumslot.png", "fitting-rig-subsystem": "texture/classes/fitting/filtericonrigslot.png", + "hardpoint-launcher": "texture/classes/fitting/iconlauncherhardpoint.png", + "hardpoint-turret": "texture/classes/fitting/iconturrethardpoint.png", "hull-hp": "texture/classes/fitting/statsicons/structurehp.png", "hull-repair-rate": "texture/classes/fitting/statsicons/hullrepairrate.png", "inertia-modifier": "texture/classes/fitting/statsicons/inertiamodifier.png", diff --git a/src/ShipFit/ShipFit.module.css b/src/ShipFit/ShipFit.module.css index ae09c5c..95a5961 100644 --- a/src/ShipFit/ShipFit.module.css +++ b/src/ShipFit/ShipFit.module.css @@ -68,6 +68,29 @@ top: 3.5%; } +.turretLauncherIcon { + height: 2.5%; + margin-top: -2%; + position: relative; + transform: rotate(var(--reverse-rotation)); + width: 2.5%; +} +.turretLauncherIcon > img { + height: 100%; + position: absolute; + width: 100%; +} +.turretLauncherItem { + border-radius: 50%; + border: 1px solid #9d9d9d; + height: 1.1%; + margin-top: -2%; + width: 1.1%; +} +.turretLauncherItemUsed { + background-color: #707070; +} + .radialMenu { filter: drop-shadow(0 0 2px #ffffff); position: absolute; diff --git a/src/ShipFit/ShipFit.tsx b/src/ShipFit/ShipFit.tsx index bb6d4c8..8a057a7 100644 --- a/src/ShipFit/ShipFit.tsx +++ b/src/ShipFit/ShipFit.tsx @@ -1,24 +1,41 @@ import React from "react"; +import clsx from "clsx"; +import { EveDataContext } from "../EveDataProvider"; import { ShipSnapshotContext } from "../ShipSnapshotProvider"; import { FitLink } from "./FitLink"; import { Hull } from "./Hull"; -import { Slot } from "./Slot"; +import { Icon } from "../Icon"; import { RadialMenu } from "./RadialMenu"; -import { RingOuter } from "./RingOuter"; import { RingInner } from "./RingInner"; +import { RingOuter } from "./RingOuter"; import { RingTop, RingTopItem } from "./RingTop"; +import { Slot } from "./Slot"; import styles from "./ShipFit.module.css"; /** * Render a ship fit similar to how it is done in-game. */ -export const ShipFit = () => { +export const ShipFit = (props: { withTurrentLauncherSlots?: boolean }) => { + const eveData = React.useContext(EveDataContext); const shipSnapshot = React.useContext(ShipSnapshotContext); const slots = shipSnapshot.slots; + let launcherSlotsUsed = + shipSnapshot.items?.filter((item) => + eveData?.typeDogma?.[item.type_id].dogmaEffects.find( + (effect) => effect.effectID === eveData.effectMapping?.launcherFitted, + ), + ).length ?? 0; + let turretSlotsUsed = + shipSnapshot.items?.filter((item) => + eveData?.typeDogma?.[item.type_id].dogmaEffects.find( + (effect) => effect.effectID === eveData.effectMapping?.turretFitted, + ), + ).length ?? 0; + return (
@@ -28,6 +45,50 @@ export const ShipFit = () => { + {props.withTurrentLauncherSlots && ( + <> + +
+ +
+
+ {Array.from({ length: slots?.turret }, (_, i) => { + turretSlotsUsed--; + return ( + +
= 0, + })} + > +   +
+
+ ); + })} + + +
+ +
+
+ {Array.from({ length: slots?.launcher }, (_, i) => { + launcherSlotsUsed--; + return ( + +
= 0, + })} + > +   +
+
+ ); + })} + + )} + diff --git a/src/ShipFitExtended/ShipFitExtended.tsx b/src/ShipFitExtended/ShipFitExtended.tsx index 8448c03..2b1391f 100644 --- a/src/ShipFitExtended/ShipFitExtended.tsx +++ b/src/ShipFitExtended/ShipFitExtended.tsx @@ -89,7 +89,7 @@ const FitName = () => { export const ShipFitExtended = () => { return (
- +
diff --git a/src/ShipSnapshotProvider/ShipSnapshotProvider.tsx b/src/ShipSnapshotProvider/ShipSnapshotProvider.tsx index 3c11718..eb346a4 100644 --- a/src/ShipSnapshotProvider/ShipSnapshotProvider.tsx +++ b/src/ShipSnapshotProvider/ShipSnapshotProvider.tsx @@ -49,6 +49,8 @@ interface ShipSnapshotSlots { lowslot: number; subsystem: number; rig: number; + launcher: number; + turret: number; } export type ShipSnapshotSlotsType = keyof ShipSnapshotSlots; @@ -89,6 +91,8 @@ export const ShipSnapshotContext = React.createContext({ lowslot: 0, subsystem: 0, rig: 0, + launcher: 0, + turret: 0, }, addModule: () => {}, removeModule: () => {}, @@ -109,6 +113,8 @@ const slotStart: Record = { lowslot: 11, subsystem: 125, rig: 92, + launcher: 27, + turret: 27, }; export interface ShipSnapshotProps { @@ -137,6 +143,8 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => { lowslot: 0, subsystem: 0, rig: 0, + launcher: 0, + turret: 0, }, addModule: () => {}, removeModule: () => {}, @@ -409,6 +417,8 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => { lowslot: 0, subsystem: 0, rig: 0, + launcher: 0, + turret: 0, }; slots.hislot = snapshot.hull.attributes.get(eveData?.attributeMapping?.hiSlots || 0)?.value || 0; @@ -416,12 +426,16 @@ export const ShipSnapshotProvider = (props: ShipSnapshotProps) => { slots.lowslot = snapshot.hull.attributes.get(eveData?.attributeMapping?.lowSlots || 0)?.value || 0; slots.subsystem = snapshot.hull.attributes.get(eveData?.attributeMapping?.maxSubSystems || 0)?.value || 0; slots.rig = snapshot.hull?.attributes.get(eveData?.attributeMapping?.rigSlots || 0)?.value || 0; + slots.launcher = snapshot.hull?.attributes.get(eveData?.attributeMapping?.launcherSlotsLeft || 0)?.value || 0; + slots.turret = snapshot.hull?.attributes.get(eveData?.attributeMapping?.turretSlotsLeft || 0)?.value || 0; const items = snapshot.items; for (const item of items) { slots.hislot += item.attributes.get(eveData?.attributeMapping?.hiSlotModifier || 0)?.value || 0; slots.medslot += item.attributes.get(eveData?.attributeMapping?.medSlotModifier || 0)?.value || 0; slots.lowslot += item.attributes.get(eveData?.attributeMapping?.lowSlotModifier || 0)?.value || 0; + slots.launcher += item.attributes.get(eveData?.attributeMapping?.launcherHardPointModifier || 0)?.value || 0; + slots.turret += item.attributes.get(eveData?.attributeMapping?.turretHardPointModifier || 0)?.value || 0; } setShipSnapshot((oldSnapshot) => {