feat: allow toggling the state of the modules (Offline, Online, Active, Overload) (#10)
This commit is contained in:
196
.storybook/fits.ts
Normal file
196
.storybook/fits.ts
Normal file
@@ -0,0 +1,196 @@
|
||||
|
||||
export const eftFit = `[Loki,Loki basic PVE]
|
||||
Caldari Navy Ballistic Control System
|
||||
Caldari Navy Ballistic Control System
|
||||
Caldari Navy Ballistic Control System
|
||||
Damage Control II
|
||||
|
||||
Gist X-Type Large Shield Booster
|
||||
Republic Fleet Large Cap Battery
|
||||
Missile Guidance Computer II
|
||||
10MN Afterburner II
|
||||
Multispectrum Shield Hardener II
|
||||
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Covert Ops Cloaking Device II
|
||||
Sisters Core Probe Launcher
|
||||
|
||||
Medium Hydraulic Bay Thrusters II
|
||||
Medium Rocket Fuel Cache Partition II
|
||||
Medium Rocket Fuel Cache Partition I
|
||||
|
||||
Loki Core - Augmented Nuclear Reactor
|
||||
Loki Defensive - Covert Reconfiguration
|
||||
Loki Offensive - Launcher Efficiency Configuration
|
||||
Loki Propulsion - Wake Limiter
|
||||
|
||||
Hammerhead II x1
|
||||
`;
|
||||
|
||||
export const fullFit = {
|
||||
"name": "C3 Ratter : NishEM",
|
||||
"ship_type_id": 29984,
|
||||
"description": "",
|
||||
"items": [
|
||||
{
|
||||
"flag": 125,
|
||||
"quantity": 1,
|
||||
"type_id": 45626
|
||||
},
|
||||
{
|
||||
"flag": 126,
|
||||
"quantity": 1,
|
||||
"type_id": 45591
|
||||
},
|
||||
{
|
||||
"flag": 127,
|
||||
"quantity": 1,
|
||||
"type_id": 45601
|
||||
},
|
||||
{
|
||||
"flag": 128,
|
||||
"quantity": 1,
|
||||
"type_id": 45615
|
||||
},
|
||||
{
|
||||
"flag": 11,
|
||||
"quantity": 1,
|
||||
"type_id": 22291
|
||||
},
|
||||
{
|
||||
"flag": 12,
|
||||
"quantity": 1,
|
||||
"type_id": 22291
|
||||
},
|
||||
{
|
||||
"flag": 13,
|
||||
"quantity": 1,
|
||||
"type_id": 22291
|
||||
},
|
||||
{
|
||||
"flag": 19,
|
||||
"quantity": 1,
|
||||
"type_id": 41218
|
||||
},
|
||||
{
|
||||
"flag": 20,
|
||||
"quantity": 1,
|
||||
"type_id": 35790
|
||||
},
|
||||
{
|
||||
"flag": 21,
|
||||
"quantity": 1,
|
||||
"type_id": 2281,
|
||||
"state": "Active"
|
||||
},
|
||||
{
|
||||
"flag": 22,
|
||||
"quantity": 1,
|
||||
"type_id": 15766
|
||||
},
|
||||
{
|
||||
"flag": 23,
|
||||
"quantity": 1,
|
||||
"type_id": 19187
|
||||
},
|
||||
{
|
||||
"flag": 24,
|
||||
"quantity": 1,
|
||||
"type_id": 19187
|
||||
},
|
||||
{
|
||||
"flag": 25,
|
||||
"quantity": 1,
|
||||
"type_id": 35790
|
||||
},
|
||||
{
|
||||
"flag": 27,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 28,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 29,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 30,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 31,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 32,
|
||||
"quantity": 1,
|
||||
"type_id": 25715
|
||||
},
|
||||
{
|
||||
"flag": 33,
|
||||
"quantity": 1,
|
||||
"type_id": 28756
|
||||
},
|
||||
{
|
||||
"flag": 92,
|
||||
"quantity": 1,
|
||||
"type_id": 31724
|
||||
},
|
||||
{
|
||||
"flag": 93,
|
||||
"quantity": 1,
|
||||
"type_id": 31824
|
||||
},
|
||||
{
|
||||
"flag": 94,
|
||||
"quantity": 1,
|
||||
"type_id": 31378
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 3720,
|
||||
"type_id": 24492
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 5472,
|
||||
"type_id": 2679
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 1,
|
||||
"type_id": 35795
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 1,
|
||||
"type_id": 35794
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 8,
|
||||
"type_id": 30486
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 1,
|
||||
"type_id": 35794
|
||||
},
|
||||
{
|
||||
"flag": 5,
|
||||
"quantity": 396,
|
||||
"type_id": 24492
|
||||
}
|
||||
]
|
||||
};
|
||||
@@ -18,7 +18,7 @@
|
||||
"author": "Patric Stout <eveshipfit@truebrain.nl>",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@eveshipfit/dogma-engine": "^1.1.0",
|
||||
"@eveshipfit/dogma-engine": "^2.0.1",
|
||||
"clsx": "^2.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { DogmaEngineContext, DogmaEngineProvider } from './';
|
||||
|
||||
@@ -28,7 +30,7 @@ const TestDogmaEngine = () => {
|
||||
const dogmaEngine = React.useContext(DogmaEngineContext);
|
||||
|
||||
if (dogmaEngine?.loaded) {
|
||||
const stats = dogmaEngine.engine?.calculate({hull: 12747, items: [20639]}, {});
|
||||
const stats = dogmaEngine.engine?.calculate(fullFit, {});
|
||||
|
||||
return (
|
||||
<div>
|
||||
|
||||
@@ -38,8 +38,8 @@ export interface DogmaEngineProps {
|
||||
* const dogmaEngine = React.useContext(DogmaEngineContext);
|
||||
*
|
||||
* if (dogmaEngine?.loaded) {
|
||||
* // calculate({hull: number, items: number[]}, skills: Map<number, number>)
|
||||
* const stats = dogmaEngine.engine.calculate({hull: 12747, items: [20639]}, []);
|
||||
* // calculate(esiFit: EsiFit, skills: Map<number, number>)
|
||||
* const stats = dogmaEngine.engine.calculate(esiFit, {});
|
||||
* console.log(stats);
|
||||
* }
|
||||
* ```
|
||||
|
||||
@@ -7,7 +7,7 @@ import { DogmaAttribute, DogmaEffect, TypeDogma, TypeID } from "./DataTypes";
|
||||
// eslint-disable-next-line import/extensions
|
||||
import * as esf_pb2 from "./esf_pb2.js";
|
||||
|
||||
const defaultDataUrl = "https://data.eveship.fit/20231023/";
|
||||
const defaultDataUrl = "https://data.eveship.fit/20231023-3/";
|
||||
|
||||
interface DogmaData {
|
||||
loaded?: boolean;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { eftFit } from '../../.storybook/fits';
|
||||
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { FormatEftToEsi } from './FormatEftToEsi';
|
||||
|
||||
@@ -23,37 +25,7 @@ type Story = StoryObj<typeof FormatEftToEsi>;
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
eft: `[Loki,Loki basic PVE]
|
||||
Caldari Navy Ballistic Control System
|
||||
Caldari Navy Ballistic Control System
|
||||
Caldari Navy Ballistic Control System
|
||||
Damage Control II
|
||||
|
||||
Gist X-Type Large Shield Booster
|
||||
Republic Fleet Large Cap Battery
|
||||
Missile Guidance Computer II
|
||||
10MN Afterburner II
|
||||
Multispectrum Shield Hardener II
|
||||
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Heavy Assault Missile Launcher II, Mjolnir Rage Heavy Assault Missile
|
||||
Covert Ops Cloaking Device II
|
||||
Sisters Core Probe Launcher
|
||||
|
||||
Medium Hydraulic Bay Thrusters II
|
||||
Medium Rocket Fuel Cache Partition II
|
||||
Medium Rocket Fuel Cache Partition I
|
||||
|
||||
Loki Core - Augmented Nuclear Reactor
|
||||
Loki Defensive - Covert Reconfiguration
|
||||
Loki Offensive - Launcher Efficiency Configuration
|
||||
Loki Propulsion - Wake Limiter
|
||||
|
||||
Hammerhead II x1
|
||||
`,
|
||||
eft: eftFit,
|
||||
},
|
||||
decorators: [withEveDataProvider],
|
||||
};
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { DogmaEngineProvider } from '../DogmaEngineProvider';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { ShipSnapshotProvider } from '../ShipSnapshotProvider';
|
||||
@@ -20,7 +22,7 @@ const withShipSnapshotProvider: Decorator<{name: string}> = (Story, context) =>
|
||||
<EveDataProvider>
|
||||
<DogmaEngineProvider>
|
||||
<ShipSnapshotProvider {...context.parameters.snapshot}>
|
||||
<Story />
|
||||
cpuUsage: <Story />
|
||||
</ShipSnapshotProvider>
|
||||
</DogmaEngineProvider>
|
||||
</EveDataProvider>
|
||||
@@ -34,7 +36,7 @@ export const Default: Story = {
|
||||
decorators: [withShipSnapshotProvider],
|
||||
parameters: {
|
||||
snapshot: {
|
||||
fit: JSON.parse("{\"name\": \"test\", \"ship_type_id\": 12747, \"items\": [{\"flag\": 11, \"quantity\": 1, \"type_id\": 20639}]}"),
|
||||
fit: fullFit,
|
||||
skills: {},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -65,22 +65,40 @@
|
||||
}
|
||||
|
||||
.slotInner {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
border-top-left-radius: 100% 4px;
|
||||
border-top-right-radius: 100% 4px;
|
||||
border: 1px solid rgba(127, 127, 127, 0.5);
|
||||
border: 1px solid black;
|
||||
box-sizing: border-box;
|
||||
height: calc(var(--radius-slots) / 7);
|
||||
left: calc(var(--radius-slots) / 8 / 2 * -1);
|
||||
left: calc(var(--radius-slots) / 7 / 2 * -1);
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
transform: perspective(8px) rotateX(-1.5deg);
|
||||
width: calc(var(--radius-slots) / 8);
|
||||
width: calc(var(--radius-slots) / 7);
|
||||
}
|
||||
|
||||
.slotInnerInvalid {
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.slotInner[data-state="Passive"] {
|
||||
background-color: #0000002d;
|
||||
border-color: #6c6c6c9f;
|
||||
opacity: 0.3;
|
||||
}
|
||||
.slotInner[data-state="Online"] {
|
||||
background-color: #9595952d;
|
||||
border-color: #9595959f;
|
||||
}
|
||||
.slotInner[data-state="Active"] {
|
||||
background-color: #87d3282d;
|
||||
border-color: #87d3289f;
|
||||
}
|
||||
.slotInner[data-state="Overload"] {
|
||||
background-color: #e8342b2d;
|
||||
border-color: #e8342b9f;
|
||||
}
|
||||
|
||||
.slotItem {
|
||||
--reverse-rotation: calc(-1 * var(--rotation));
|
||||
left: -32px;
|
||||
@@ -89,6 +107,10 @@
|
||||
transform: rotate(var(--reverse-rotation)) scale(calc(var(--scale) * 0.8));
|
||||
}
|
||||
|
||||
.slotItemOffline {
|
||||
opacity: 0.3;
|
||||
}
|
||||
|
||||
.slotItem > img {
|
||||
border-top-left-radius: 32px;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { DogmaEngineProvider } from '../DogmaEngineProvider';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { ShipSnapshotProvider } from '../ShipSnapshotProvider';
|
||||
@@ -34,7 +36,7 @@ export const Default: Story = {
|
||||
decorators: [withShipSnapshotProvider],
|
||||
parameters: {
|
||||
snapshot: {
|
||||
fit: {"name": "C3 Ratter : NishEM", "ship_type_id": 29984, "description": "", "items": [{"flag": 125, "quantity": 1, "type_id": 45626}, {"flag": 126, "quantity": 1, "type_id": 45591}, {"flag": 127, "quantity": 1, "type_id": 45601}, {"flag": 128, "quantity": 1, "type_id": 45615}, {"flag": 11, "quantity": 1, "type_id": 22291}, {"flag": 12, "quantity": 1, "type_id": 22291}, {"flag": 13, "quantity": 1, "type_id": 22291}, {"flag": 19, "quantity": 1, "type_id": 41218}, {"flag": 20, "quantity": 1, "type_id": 35790}, {"flag": 21, "quantity": 1, "type_id": 2281}, {"flag": 22, "quantity": 1, "type_id": 15766}, {"flag": 23, "quantity": 1, "type_id": 19187}, {"flag": 24, "quantity": 1, "type_id": 19187}, {"flag": 25, "quantity": 1, "type_id": 35790}, {"flag": 27, "quantity": 1, "type_id": 25715}, {"flag": 28, "quantity": 1, "type_id": 25715}, {"flag": 29, "quantity": 1, "type_id": 25715}, {"flag": 30, "quantity": 1, "type_id": 25715}, {"flag": 31, "quantity": 1, "type_id": 25715}, {"flag": 32, "quantity": 1, "type_id": 25715}, {"flag": 33, "quantity": 1, "type_id": 28756}, {"flag": 92, "quantity": 1, "type_id": 31724}, {"flag": 93, "quantity": 1, "type_id": 31824}, {"flag": 94, "quantity": 1, "type_id": 31378}, {"flag": 5, "quantity": 3720, "type_id": 24492}, {"flag": 5, "quantity": 5472, "type_id": 2679}, {"flag": 5, "quantity": 1, "type_id": 35795}, {"flag": 5, "quantity": 1, "type_id": 35794}, {"flag": 5, "quantity": 8, "type_id": 30486}, {"flag": 5, "quantity": 1, "type_id": 35794}, {"flag": 5, "quantity": 396, "type_id": 24492}]},
|
||||
fit: fullFit,
|
||||
skills: {},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -24,6 +24,13 @@ const esiFlagMapping: Record<string, number[]> = {
|
||||
],
|
||||
};
|
||||
|
||||
const stateRotation: Record<string, string[]> = {
|
||||
"Passive": ["Passive"],
|
||||
"Online": ["Passive", "Online"],
|
||||
"Active": ["Passive", "Online", "Active"],
|
||||
"Overload": ["Passive", "Online", "Active", "Overload"],
|
||||
};
|
||||
|
||||
export const Slot = (props: {type: string, index: number, fittable: boolean, rotation: string}) => {
|
||||
const eveData = React.useContext(EveDataContext);
|
||||
const shipSnapshot = React.useContext(ShipSnapshotContext);
|
||||
@@ -31,7 +38,7 @@ export const Slot = (props: {type: string, index: number, fittable: boolean, rot
|
||||
const rotationStyle = { "--rotation": props.rotation } as React.CSSProperties;
|
||||
const esiFlag = esiFlagMapping[props.type][props.index - 1];
|
||||
|
||||
const esiItem = shipSnapshot?.fit?.items.find((item) => item.flag == esiFlag);
|
||||
const esiItem = shipSnapshot?.items?.find((item) => item.flag == esiFlag);
|
||||
let item = <></>;
|
||||
|
||||
/* Not fittable and nothing fitted; no need to render the slot. */
|
||||
@@ -43,10 +50,28 @@ export const Slot = (props: {type: string, index: number, fittable: boolean, rot
|
||||
item = <img src={`https://images.evetech.net/types/${esiItem.type_id}/icon?size=64`} title={eveData?.typeIDs?.[esiItem.type_id].name} />
|
||||
}
|
||||
|
||||
return <div className={styles.slot} style={rotationStyle}>
|
||||
<div className={ctlx(styles.slotInner, { [styles.slotInnerInvalid]: !props.fittable })}>
|
||||
const isOffline = esiItem?.state === "Passive" && esiItem?.max_state !== "Passive";
|
||||
|
||||
function cycleState(e: React.MouseEvent<HTMLDivElement, MouseEvent>) {
|
||||
if (!shipSnapshot?.loaded || !esiItem) return;
|
||||
|
||||
const states = stateRotation[esiItem.max_state];
|
||||
const stateIndex = states.indexOf(esiItem.state);
|
||||
|
||||
let newState;
|
||||
if (e.shiftKey) {
|
||||
newState = states[(stateIndex - 1 + states.length) % states.length];
|
||||
} else {
|
||||
newState = states[(stateIndex + 1) % states.length];
|
||||
}
|
||||
|
||||
shipSnapshot.setItemState(esiItem.flag, newState);
|
||||
}
|
||||
|
||||
return <div className={styles.slot} style={rotationStyle} onClick={cycleState}>
|
||||
<div className={ctlx(styles.slotInner, { [styles.slotInnerInvalid]: !props.fittable, })} data-state={esiItem?.state}>
|
||||
</div>
|
||||
<div className={styles.slotItem}>
|
||||
<div className={ctlx(styles.slotItem, { [styles.slotItemOffline]: isOffline })}>
|
||||
{item}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { DogmaEngineProvider } from '../DogmaEngineProvider';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { ShipSnapshotProvider } from '../ShipSnapshotProvider';
|
||||
@@ -34,7 +36,7 @@ export const Default: Story = {
|
||||
decorators: [withShipSnapshotProvider],
|
||||
parameters: {
|
||||
snapshot: {
|
||||
fit: {"name": "C3 Ratter : NishEM", "ship_type_id": 29984, "description": "", "items": [{"flag": 125, "quantity": 1, "type_id": 45626}, {"flag": 126, "quantity": 1, "type_id": 45591}, {"flag": 127, "quantity": 1, "type_id": 45601}, {"flag": 128, "quantity": 1, "type_id": 45615}, {"flag": 11, "quantity": 1, "type_id": 22291}, {"flag": 12, "quantity": 1, "type_id": 22291}, {"flag": 13, "quantity": 1, "type_id": 22291}, {"flag": 19, "quantity": 1, "type_id": 41218}, {"flag": 20, "quantity": 1, "type_id": 35790}, {"flag": 21, "quantity": 1, "type_id": 2281}, {"flag": 22, "quantity": 1, "type_id": 15766}, {"flag": 23, "quantity": 1, "type_id": 19187}, {"flag": 24, "quantity": 1, "type_id": 19187}, {"flag": 25, "quantity": 1, "type_id": 35790}, {"flag": 27, "quantity": 1, "type_id": 25715}, {"flag": 28, "quantity": 1, "type_id": 25715}, {"flag": 29, "quantity": 1, "type_id": 25715}, {"flag": 30, "quantity": 1, "type_id": 25715}, {"flag": 31, "quantity": 1, "type_id": 25715}, {"flag": 32, "quantity": 1, "type_id": 25715}, {"flag": 33, "quantity": 1, "type_id": 28756}, {"flag": 92, "quantity": 1, "type_id": 31724}, {"flag": 93, "quantity": 1, "type_id": 31824}, {"flag": 94, "quantity": 1, "type_id": 31378}, {"flag": 5, "quantity": 3720, "type_id": 24492}, {"flag": 5, "quantity": 5472, "type_id": 2679}, {"flag": 5, "quantity": 1, "type_id": 35795}, {"flag": 5, "quantity": 1, "type_id": 35794}, {"flag": 5, "quantity": 8, "type_id": 30486}, {"flag": 5, "quantity": 1, "type_id": 35794}, {"flag": 5, "quantity": 396, "type_id": 24492}]},
|
||||
fit: fullFit,
|
||||
skills: {},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -78,10 +78,10 @@ export const ShipFitExtended = (props: ShipFitExtendedProps) => {
|
||||
|
||||
<div className={styles.cpuPg}>
|
||||
<CpuPg title="CPU">
|
||||
<ShipAttribute name="cpuUsage" fixed={1} />/<ShipAttribute name="cpuOutput" fixed={1} />
|
||||
<ShipAttribute name="cpuUnused" fixed={1} />/<ShipAttribute name="cpuOutput" fixed={1} />
|
||||
</CpuPg>
|
||||
<CpuPg title="Power Grid">
|
||||
<ShipAttribute name="powerUsage" fixed={1} />/<ShipAttribute name="powerOutput" fixed={1} />
|
||||
<ShipAttribute name="powerUnused" fixed={1} />/<ShipAttribute name="powerOutput" fixed={1} />
|
||||
</CpuPg>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { EveDataContext, EveDataProvider } from '../EveDataProvider';
|
||||
import { DogmaEngineProvider } from '../DogmaEngineProvider';
|
||||
import { ShipSnapshotItemAttribute, ShipSnapshotContext, ShipSnapshotProvider } from './';
|
||||
@@ -39,7 +41,7 @@ const TestShipSnapshot = () => {
|
||||
|
||||
export const Default: Story = {
|
||||
args: {
|
||||
fit: {"name": "test", description: "", "ship_type_id": 29984, "items": [{"flag": 11, "quantity": 1, "type_id": 20639}]},
|
||||
fit: fullFit,
|
||||
skills: {},
|
||||
},
|
||||
render: (args) => (
|
||||
|
||||
@@ -12,6 +12,10 @@ export interface ShipSnapshotItemAttribute {
|
||||
|
||||
export interface ShipSnapshotItem {
|
||||
type_id: number,
|
||||
quantity: number,
|
||||
flag: number,
|
||||
state: string,
|
||||
max_state: string,
|
||||
attributes: Map<number, ShipSnapshotItemAttribute>,
|
||||
effects: number[],
|
||||
}
|
||||
@@ -24,6 +28,7 @@ export interface EsiFit {
|
||||
flag: number;
|
||||
type_id: number;
|
||||
quantity: number;
|
||||
state?: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
@@ -33,69 +38,75 @@ interface ShipSnapshot {
|
||||
items?: ShipSnapshotItem[];
|
||||
|
||||
fit?: EsiFit;
|
||||
|
||||
setItemState: (flag: number, state: string) => void;
|
||||
}
|
||||
|
||||
export const ShipSnapshotContext = React.createContext<ShipSnapshot>({});
|
||||
export const ShipSnapshotContext = React.createContext<ShipSnapshot>({
|
||||
loaded: undefined,
|
||||
setItemState: () => {},
|
||||
});
|
||||
|
||||
export interface ShipSnapshotProps {
|
||||
/** Children that can use this provider. */
|
||||
children: React.ReactNode;
|
||||
/** A ship fit in ESI representation. */
|
||||
fit: EsiFit;
|
||||
/** A list of skills to apply to the fit (skill_id, skill_level). */
|
||||
/** A list of skills to apply to the fit: {skill_id: skill_level}. */
|
||||
skills: Record<number, number>;
|
||||
}
|
||||
|
||||
const EsiFlagMapping = [
|
||||
11, 12, 13, 14, 15, 16, 17, 18, // lowslot
|
||||
19, 20, 21, 22, 23, 24, 25, 26, // medslot
|
||||
27, 28, 29, 30, 31, 32, 33, 34, // hislot
|
||||
92, 93, 94, // rig
|
||||
125, 126, 127, 128, // subsystem
|
||||
];
|
||||
|
||||
function esiFitToDogmaFit(fit: EsiFit): {
|
||||
hull: number,
|
||||
items: number[],
|
||||
} {
|
||||
const dogmaFit: {
|
||||
hull: number,
|
||||
items: number[],
|
||||
} = {
|
||||
"hull": fit.ship_type_id,
|
||||
"items": [],
|
||||
}
|
||||
|
||||
for (const item of fit.items) {
|
||||
if (EsiFlagMapping.includes(item.flag)) {
|
||||
dogmaFit.items.push(item.type_id);
|
||||
}
|
||||
}
|
||||
|
||||
return dogmaFit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the current attrbitues and applied effects of a ship fit.
|
||||
*/
|
||||
export const ShipSnapshotProvider = (props: ShipSnapshotProps) => {
|
||||
const [shipSnapshot, setShipSnapshot] = React.useState<ShipSnapshot>({});
|
||||
const [shipSnapshot, setShipSnapshot] = React.useState<ShipSnapshot>({
|
||||
loaded: undefined,
|
||||
setItemState: () => {},
|
||||
});
|
||||
const [currentFit, setCurrentFit] = React.useState<EsiFit | undefined>(undefined);
|
||||
const dogmaEngine = React.useContext(DogmaEngineContext);
|
||||
|
||||
const setItemState = React.useCallback((flag: number, state: string) => {
|
||||
if (!currentFit) return;
|
||||
|
||||
setCurrentFit((oldFit: EsiFit | undefined) => {
|
||||
if (!oldFit) return oldFit;
|
||||
|
||||
return {
|
||||
...oldFit,
|
||||
items: oldFit?.items?.map((item) => {
|
||||
if (item.flag === flag) {
|
||||
return {
|
||||
...item,
|
||||
state: state,
|
||||
};
|
||||
}
|
||||
|
||||
return item;
|
||||
}),
|
||||
};
|
||||
})
|
||||
}, [currentFit]);
|
||||
|
||||
React.useEffect(() => {
|
||||
if (!dogmaEngine.loaded) return;
|
||||
if (!props.fit || !props.skills) return;
|
||||
if (!currentFit || !props.skills) return;
|
||||
|
||||
const dogmaFit = esiFitToDogmaFit(props.fit);
|
||||
const snapshot = dogmaEngine.engine?.calculate(dogmaFit, props.skills);
|
||||
const snapshot = dogmaEngine.engine?.calculate(currentFit, props.skills);
|
||||
|
||||
setShipSnapshot({
|
||||
loaded: true,
|
||||
hull: snapshot.hull,
|
||||
items: snapshot.items,
|
||||
fit: props.fit,
|
||||
fit: currentFit,
|
||||
setItemState,
|
||||
});
|
||||
}, [dogmaEngine, props.fit, props.skills]);
|
||||
}, [dogmaEngine, currentFit, props.skills, setItemState]);
|
||||
|
||||
React.useEffect(() => {
|
||||
setCurrentFit(props.fit);
|
||||
}, [props.fit]);
|
||||
|
||||
return <ShipSnapshotContext.Provider value={shipSnapshot}>
|
||||
{props.children}
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import type { Decorator, Meta, StoryObj } from '@storybook/react';
|
||||
import React from "react";
|
||||
|
||||
import { fullFit } from '../../.storybook/fits';
|
||||
|
||||
import { DogmaEngineProvider } from '../DogmaEngineProvider';
|
||||
import { EveDataProvider } from '../EveDataProvider';
|
||||
import { ShipSnapshotProvider } from '../ShipSnapshotProvider';
|
||||
@@ -31,7 +33,7 @@ export const Default: Story = {
|
||||
decorators: [withShipSnapshotProvider],
|
||||
parameters: {
|
||||
snapshot: {
|
||||
fit: JSON.parse("{\"name\": \"test\", \"ship_type_id\": 12747, \"items\": [{\"flag\": 11, \"quantity\": 1, \"type_id\": 20639}]}"),
|
||||
fit: fullFit,
|
||||
skills: {},
|
||||
}
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user