feat: show launcher/turret slots and usage above fit (#112)

This commit is contained in:
Patric Stout
2024-05-12 11:54:50 +02:00
committed by GitHub
parent 1888f8fced
commit 8d0764d0fa
7 changed files with 120 additions and 12 deletions

View File

@@ -16,6 +16,7 @@ interface DogmaData {
typeDogma?: Record<string, TypeDogma>;
dogmaEffects?: Record<string, DogmaEffect>;
dogmaAttributes?: Record<string, DogmaAttribute>;
effectMapping?: Record<string, number>;
attributeMapping?: Record<string, number>;
}
@@ -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<string, number> = {};
for (const id in dogmaData.dogmaAttributes) {
const name = dogmaData.dogmaAttributes[id].name;
attributeMapping[name] = parseInt(id);
}
const effectMapping: Record<string, number> = {};
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 <EveDataContext.Provider value={dogmaData}>{props.children}</EveDataContext.Provider>;
};

View File

@@ -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";
}
})

View File

@@ -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",

View File

@@ -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;

View File

@@ -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 (
<div className={styles.fit}>
<RingOuter />
@@ -28,6 +45,50 @@ export const ShipFit = () => {
<FitLink />
<RingTop>
{props.withTurrentLauncherSlots && (
<>
<RingTopItem rotation={-45}>
<div className={styles.turretLauncherIcon}>
<Icon name="hardpoint-turret" size={16} />
</div>
</RingTopItem>
{Array.from({ length: slots?.turret }, (_, i) => {
turretSlotsUsed--;
return (
<RingTopItem key={i} rotation={-40 + i * 3}>
<div
className={clsx(styles.turretLauncherItem, {
[styles.turretLauncherItemUsed]: turretSlotsUsed >= 0,
})}
>
&nbsp;
</div>
</RingTopItem>
);
})}
<RingTopItem rotation={43}>
<div className={styles.turretLauncherIcon}>
<Icon name="hardpoint-launcher" size={16} />
</div>
</RingTopItem>
{Array.from({ length: slots?.launcher }, (_, i) => {
launcherSlotsUsed--;
return (
<RingTopItem key={i} rotation={39 - i * 3}>
<div
className={clsx(styles.turretLauncherItem, {
[styles.turretLauncherItemUsed]: launcherSlotsUsed >= 0,
})}
>
&nbsp;
</div>
</RingTopItem>
);
})}
</>
)}
<RingTopItem rotation={-45}>
<RadialMenu type="hislot" />
</RingTopItem>

View File

@@ -89,7 +89,7 @@ const FitName = () => {
export const ShipFitExtended = () => {
return (
<div className={styles.fit}>
<ShipFit />
<ShipFit withTurrentLauncherSlots />
<div className={styles.fitName}>
<FitName />

View File

@@ -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<ShipSnapshot>({
lowslot: 0,
subsystem: 0,
rig: 0,
launcher: 0,
turret: 0,
},
addModule: () => {},
removeModule: () => {},
@@ -109,6 +113,8 @@ const slotStart: Record<ShipSnapshotSlotsType, number> = {
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) => {