port them all
This commit is contained in:
parent
82331d1f26
commit
11b89b308a
@ -1,76 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
import _ from 'lodash';
|
||||
|
||||
import reqs from "./reqs.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { reqs },
|
||||
initial: {
|
||||
bays: 0,
|
||||
squadrons: [],
|
||||
},
|
||||
actions: {
|
||||
setCarrierBays: null,
|
||||
setSquadronType: null,
|
||||
}
|
||||
});
|
||||
|
||||
dux.setMutation( 'setCarrierBays', bays => u({bays, reqs:
|
||||
calcBaysReqs(bays),
|
||||
squadrons: adjustSquadrons(bays),
|
||||
}) );
|
||||
|
||||
dux.setMutation('setSquadronType', ({type, id}) => state => {
|
||||
|
||||
return u.updateIn(['squadrons', id-1], {
|
||||
type,
|
||||
reqs: squadronReqs(type)
|
||||
}, state )
|
||||
|
||||
} );
|
||||
|
||||
export const squadronTypes= [
|
||||
{ type: "standard", cost: 3 },
|
||||
{ type: "fast", cost: 4 },
|
||||
{ type: "heavy", cost: 5 },
|
||||
{ type: "interceptor", cost: 3 },
|
||||
{ type: "attack", cost: 4 },
|
||||
{ type: "long range", cost: 4 },
|
||||
{ type: "torpedo", cost: 6 },
|
||||
];
|
||||
|
||||
function squadronReqs(type) {
|
||||
return { mass: 6, cost: 6 * squadronTypes.find( s => s.type === type )?.cost }
|
||||
}
|
||||
|
||||
|
||||
const adjustSquadrons = bays => squadrons => {
|
||||
if( squadrons.length > bays ) {
|
||||
squadrons = squadrons.slice(0,bays);
|
||||
}
|
||||
|
||||
if( squadrons.length < bays ) {
|
||||
squadrons = [ ...squadrons, ..._.times(
|
||||
bays - squadrons.length, () => ({
|
||||
type: squadronTypes[0].type,
|
||||
reqs: {
|
||||
cost: 6 * squadronTypes[0].cost,
|
||||
mass: 6,
|
||||
},
|
||||
})
|
||||
)];
|
||||
}
|
||||
|
||||
return squadrons;
|
||||
|
||||
}
|
||||
|
||||
function calcBaysReqs(bays) {
|
||||
return {
|
||||
mass: 9 * bays,
|
||||
cost: 18 * bays,
|
||||
}
|
||||
}
|
||||
|
||||
export default dux;
|
79
src/lib/shipDux/carrier.ts
Normal file
79
src/lib/shipDux/carrier.ts
Normal file
@ -0,0 +1,79 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs, Reqs } from "./reqs";
|
||||
|
||||
type Squadron = {
|
||||
type: string;
|
||||
reqs: Reqs;
|
||||
};
|
||||
|
||||
const initialState = {
|
||||
bays: 0,
|
||||
squadrons: [] as Squadron[],
|
||||
reqs,
|
||||
};
|
||||
|
||||
export const carrierSlice = createSlice({
|
||||
name: "carrier",
|
||||
initialState,
|
||||
reducers: {
|
||||
setCarrierBays: (state, action: PayloadAction<number>) => {
|
||||
state.bays = action.payload;
|
||||
state.reqs = calcBaysReqs(action.payload);
|
||||
state.squadrons = adjustSquadrons(action.payload)(state.squadrons);
|
||||
},
|
||||
setSquadronType: (
|
||||
state,
|
||||
action: PayloadAction<{ type: string; id: number }>
|
||||
) => {
|
||||
state.squadrons[action.payload.id - 1] = {
|
||||
type: action.payload.type,
|
||||
reqs: squadronReqs(action.payload.type),
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const squadronTypes = [
|
||||
{ type: "standard", cost: 3 },
|
||||
{ type: "fast", cost: 4 },
|
||||
{ type: "heavy", cost: 5 },
|
||||
{ type: "interceptor", cost: 3 },
|
||||
{ type: "attack", cost: 4 },
|
||||
{ type: "long range", cost: 4 },
|
||||
{ type: "torpedo", cost: 6 },
|
||||
];
|
||||
|
||||
function squadronReqs(type: string) {
|
||||
return {
|
||||
mass: 6,
|
||||
cost: 6 * squadronTypes.find((s) => s.type === type)?.cost,
|
||||
};
|
||||
}
|
||||
|
||||
const adjustSquadrons = (bays) => (squadrons) => {
|
||||
if (squadrons.length > bays) {
|
||||
squadrons = squadrons.slice(0, bays);
|
||||
}
|
||||
|
||||
if (squadrons.length < bays) {
|
||||
squadrons = [
|
||||
...squadrons,
|
||||
..._.times(bays - squadrons.length, () => ({
|
||||
type: squadronTypes[0].type,
|
||||
reqs: {
|
||||
cost: 6 * squadronTypes[0].cost,
|
||||
mass: 6,
|
||||
},
|
||||
})),
|
||||
];
|
||||
}
|
||||
|
||||
return squadrons;
|
||||
};
|
||||
|
||||
function calcBaysReqs(bays) {
|
||||
return {
|
||||
mass: 9 * bays,
|
||||
cost: 18 * bays,
|
||||
};
|
||||
}
|
26
src/lib/shipDux/combineSlices.ts
Normal file
26
src/lib/shipDux/combineSlices.ts
Normal file
@ -0,0 +1,26 @@
|
||||
import { combineReducers } from "redux";
|
||||
import { createAction, Slice } from "@reduxjs/toolkit";
|
||||
import * as R from "remeda";
|
||||
|
||||
type MergedActions<S extends { actions: any }> = S["actions"];
|
||||
|
||||
export default function combineSlices<
|
||||
S extends Record<string, Slice> = Record<string, Slice>
|
||||
>(slices: S) {
|
||||
const reducer = combineReducers(R.mapValues(slices, R.prop("reducer")));
|
||||
const actions: MergedActions<S[keyof S]> = Object.values(slices)
|
||||
.map(R.prop("actions"))
|
||||
.map(Object.values)
|
||||
.flat() as any;
|
||||
|
||||
return { reducer, actions };
|
||||
}
|
||||
|
||||
const x = combineSlices({
|
||||
a: {
|
||||
reducer: (state) => state,
|
||||
actions: {
|
||||
a: createAction("a"),
|
||||
},
|
||||
},
|
||||
});
|
@ -1,28 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import reqs from "./reqs.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { reqs },
|
||||
initial: {
|
||||
rating: 1,
|
||||
advanced: false,
|
||||
},
|
||||
actions: {
|
||||
setDrive: null,
|
||||
setDriveReqs: null,
|
||||
},
|
||||
});
|
||||
|
||||
dux.setMutation("setDrive", (changes) => u(changes));
|
||||
dux.setMutation("setDriveReqs", (reqs) => u({ reqs }));
|
||||
|
||||
export function calcDriveReqs(shipMass, rating, advanced = false) {
|
||||
const mass = Math.ceil(rating * 0.05 * shipMass);
|
||||
const cost = mass * (advanced ? 3 : 2);
|
||||
|
||||
return { mass, cost };
|
||||
}
|
||||
|
||||
export default dux;
|
40
src/lib/shipDux/engine.ts
Normal file
40
src/lib/shipDux/engine.ts
Normal file
@ -0,0 +1,40 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import { Reqs, reqs } from "./reqs.js";
|
||||
|
||||
const initialState = {
|
||||
rating: 1,
|
||||
advanced: false,
|
||||
reqs,
|
||||
};
|
||||
|
||||
const engine = createSlice({
|
||||
name: "engine",
|
||||
initialState,
|
||||
reducers: {
|
||||
setDriveRating(state, action: PayloadAction<number>) {
|
||||
state.rating = action.payload;
|
||||
},
|
||||
setDriveAdvanced(state, action: PayloadAction<boolean>) {
|
||||
state.advanced = action.payload;
|
||||
},
|
||||
setDriverReqs(state, action: PayloadAction<Reqs>) {
|
||||
state.reqs = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function calcDriveReqs(
|
||||
shipMass: number,
|
||||
rating: number,
|
||||
advanced = false
|
||||
) {
|
||||
const mass = Math.ceil(rating * 0.05 * shipMass);
|
||||
const cost = mass * (advanced ? 3 : 2);
|
||||
|
||||
return { mass, cost };
|
||||
}
|
||||
|
||||
export default engine;
|
@ -1,13 +1,13 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import carrier from './carrier.js';
|
||||
import carrier from "./carrier.js";
|
||||
|
||||
const dux = new Updux({
|
||||
actions: {
|
||||
setShipType: null,
|
||||
setShipClass: null,
|
||||
setCarrierBays: carrier.actions.setCarrierBays,
|
||||
setCarrierBays: carrier.actions.setCarrierBays,
|
||||
},
|
||||
initial: {
|
||||
shipType: "",
|
||||
@ -19,8 +19,10 @@ const dux = new Updux({
|
||||
|
||||
dux.setMutation("setShipType", (shipType) => u({ shipType }));
|
||||
dux.setMutation("setShipClass", (shipClass) => u({ shipClass }));
|
||||
dux.setMutation('setCarrierBays', (bays) => u({
|
||||
dux.setMutation("setCarrierBays", (bays) =>
|
||||
u({
|
||||
isCarrier: bays > 0,
|
||||
}))
|
||||
})
|
||||
);
|
||||
|
||||
export default dux;
|
@ -1,109 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import propulsion from "./propulsion/index.js";
|
||||
import identification from "./identification.js";
|
||||
import { calculateDriveReqs } from "./propulsion/drive.js";
|
||||
import { ftlReqsReaction } from "./propulsion/ftl.js";
|
||||
import structure from "./structure/index.js";
|
||||
import carrier from "./carrier.js";
|
||||
import weaponry from "./weaponry/index.js";
|
||||
import { screensReqsReaction } from "./structure/screens.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
identification,
|
||||
propulsion,
|
||||
structure,
|
||||
carrier,
|
||||
weaponry,
|
||||
},
|
||||
initial: {
|
||||
reqs: { cost: 0, mass: 10, usedMass: 0 },
|
||||
},
|
||||
actions: {
|
||||
setShipReqs: null,
|
||||
setUITransform: null,
|
||||
resetLayout: null,
|
||||
resetShip: null,
|
||||
},
|
||||
});
|
||||
|
||||
function resetUITransform(thing) {
|
||||
if (typeof thing !== "object") return thing;
|
||||
|
||||
return u.map(
|
||||
(v, k) => (k === "uiTransform" ? "" : resetUITransform(v)),
|
||||
thing
|
||||
);
|
||||
}
|
||||
|
||||
dux.setMutation("resetShip", () => () => dux.initial);
|
||||
|
||||
dux.setMutation("resetLayout", () => resetUITransform);
|
||||
|
||||
dux.setMutation("setShipMass", (mass) => u({ reqs: { mass } }));
|
||||
dux.setMutation("setShipReqs", (reqs) => u({ reqs }));
|
||||
|
||||
dux.setMutation("setUITransform", ({ system, systemId, translate }) => {
|
||||
const transform = translate
|
||||
? `translate(${translate[0]}px,${translate[1]}px)`
|
||||
: "";
|
||||
|
||||
switch (system) {
|
||||
case "firecons":
|
||||
return u.updateIn("weaponry.firecons.uiTransform", transform);
|
||||
|
||||
case "weapon":
|
||||
return u.updateIn(
|
||||
"weaponry.weapons",
|
||||
u.map(u.if(({ id }) => id === systemId, u({ uiTransform: transform })))
|
||||
);
|
||||
|
||||
case "screens":
|
||||
return u.updateIn("structure.screens.uiTransform", transform);
|
||||
|
||||
case "hull":
|
||||
return u.updateIn("structure.hull.uiTransform", transform);
|
||||
|
||||
case "internalSystems":
|
||||
const path = "structure.uiTransform";
|
||||
return u.updateIn(path, transform);
|
||||
|
||||
case "ftl":
|
||||
return u.updateIn("propulsion.ftl.uiTransform", transform);
|
||||
|
||||
case "drive":
|
||||
return u.updateIn("propulsion.drive.uiTransform", transform);
|
||||
|
||||
default:
|
||||
return (state) => state;
|
||||
}
|
||||
});
|
||||
|
||||
dux.addReaction(calculateDriveReqs);
|
||||
dux.addReaction(ftlReqsReaction);
|
||||
dux.addReaction(screensReqsReaction);
|
||||
|
||||
dux.addReaction((store) => (state) => {
|
||||
let cost = 0;
|
||||
let mass = 0;
|
||||
|
||||
let subsystems = Object.values(state);
|
||||
|
||||
while (subsystems.length > 0) {
|
||||
const subsystem = subsystems.shift();
|
||||
if (typeof subsystem !== "object") continue;
|
||||
|
||||
if (subsystem.reqs) {
|
||||
cost += subsystem.reqs.cost;
|
||||
mass += subsystem.reqs.mass;
|
||||
}
|
||||
|
||||
subsystems.push(...Object.values(subsystem));
|
||||
}
|
||||
|
||||
store.dispatch.setShipReqs({ cost, usedMass: mass });
|
||||
});
|
||||
|
||||
export default dux;
|
106
src/lib/shipDux/index.ts
Normal file
106
src/lib/shipDux/index.ts
Normal file
@ -0,0 +1,106 @@
|
||||
import * as propulsion from "./propulsion/index.js";
|
||||
import * as identification from "./identification.js";
|
||||
import { calculateDriveReqs } from "./propulsion/drive.js";
|
||||
import { ftlReqsReaction } from "./propulsion/ftl.js";
|
||||
import * as structure from "./structure/index.js";
|
||||
import * as carrier from "./carrier.js";
|
||||
import * as weaponry from "./weaponry/index.js";
|
||||
import { screensReqsReaction } from "./structure/screens.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
identification,
|
||||
propulsion,
|
||||
structure,
|
||||
carrier,
|
||||
weaponry,
|
||||
},
|
||||
initial: {
|
||||
reqs: { cost: 0, mass: 10, usedMass: 0 },
|
||||
},
|
||||
actions: {
|
||||
setShipReqs: null,
|
||||
setUITransform: null,
|
||||
resetLayout: null,
|
||||
resetShip: null,
|
||||
},
|
||||
});
|
||||
|
||||
function resetUITransform(thing) {
|
||||
if (typeof thing !== "object") return thing;
|
||||
|
||||
return u.map(
|
||||
(v, k) => (k === "uiTransform" ? "" : resetUITransform(v)),
|
||||
thing
|
||||
);
|
||||
}
|
||||
|
||||
dux.setMutation("resetShip", () => () => dux.initial);
|
||||
|
||||
dux.setMutation("resetLayout", () => resetUITransform);
|
||||
|
||||
dux.setMutation("setShipMass", (mass) => u({ reqs: { mass } }));
|
||||
dux.setMutation("setShipReqs", (reqs) => u({ reqs }));
|
||||
|
||||
dux.setMutation("setUITransform", ({ system, systemId, translate }) => {
|
||||
const transform = translate
|
||||
? `translate(${translate[0]}px,${translate[1]}px)`
|
||||
: "";
|
||||
|
||||
switch (system) {
|
||||
case "firecons":
|
||||
return u.updateIn("weaponry.firecons.uiTransform", transform);
|
||||
|
||||
case "weapon":
|
||||
return u.updateIn(
|
||||
"weaponry.weapons",
|
||||
u.map(u.if(({ id }) => id === systemId, u({ uiTransform: transform })))
|
||||
);
|
||||
|
||||
case "screens":
|
||||
return u.updateIn("structure.screens.uiTransform", transform);
|
||||
|
||||
case "hull":
|
||||
return u.updateIn("structure.hull.uiTransform", transform);
|
||||
|
||||
case "internalSystems":
|
||||
const path = "structure.uiTransform";
|
||||
return u.updateIn(path, transform);
|
||||
|
||||
case "ftl":
|
||||
return u.updateIn("propulsion.ftl.uiTransform", transform);
|
||||
|
||||
case "drive":
|
||||
return u.updateIn("propulsion.drive.uiTransform", transform);
|
||||
|
||||
default:
|
||||
return (state) => state;
|
||||
}
|
||||
});
|
||||
|
||||
dux.addReaction(calculateDriveReqs);
|
||||
dux.addReaction(ftlReqsReaction);
|
||||
dux.addReaction(screensReqsReaction);
|
||||
|
||||
dux.addReaction((store) => (state) => {
|
||||
let cost = 0;
|
||||
let mass = 0;
|
||||
|
||||
let subsystems = Object.values(state);
|
||||
|
||||
while (subsystems.length > 0) {
|
||||
const subsystem = subsystems.shift();
|
||||
if (typeof subsystem !== "object") continue;
|
||||
|
||||
if (subsystem.reqs) {
|
||||
cost += subsystem.reqs.cost;
|
||||
mass += subsystem.reqs.mass;
|
||||
}
|
||||
|
||||
subsystems.push(...Object.values(subsystem));
|
||||
}
|
||||
|
||||
store.dispatch.setShipReqs({ cost, usedMass: mass });
|
||||
});
|
||||
|
||||
export default dux;
|
@ -1,41 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
import reqs from "../reqs.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { reqs },
|
||||
initial: {
|
||||
rating: 0,
|
||||
advanced: false,
|
||||
},
|
||||
actions: {
|
||||
setDrive: null,
|
||||
setDriveReqs: null,
|
||||
},
|
||||
});
|
||||
|
||||
dux.setMutation("setDrive", (changes) => u(changes));
|
||||
dux.setMutation("setDriveReqs", (reqs) => u({ reqs }));
|
||||
|
||||
// needs to be at the top level
|
||||
export const calculateDriveReqs = (store) =>
|
||||
createSelector(
|
||||
[
|
||||
(ship) => ship.reqs.mass,
|
||||
(ship) => ship.propulsion.drive.rating,
|
||||
(ship) => ship.propulsion.drive.advanced,
|
||||
],
|
||||
(ship_mass, rating, advanced) =>
|
||||
store.dispatch.setDriveReqs(calcDriveReqs(ship_mass, rating, advanced))
|
||||
);
|
||||
|
||||
export function calcDriveReqs(shipMass, rating, advanced = false) {
|
||||
const mass = Math.ceil(rating * 0.05 * shipMass);
|
||||
const cost = mass * (advanced ? 3 : 2);
|
||||
|
||||
return { mass, cost };
|
||||
}
|
||||
|
||||
export default dux;
|
50
src/lib/shipDux/propulsion/drive.ts
Normal file
50
src/lib/shipDux/propulsion/drive.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { PayloadAction, createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs, Reqs } from "../reqs";
|
||||
|
||||
type DriveProps = {
|
||||
rating: number;
|
||||
advanced: boolean;
|
||||
};
|
||||
|
||||
const initialState: DriveProps & { reqs: Reqs } = {
|
||||
rating: 0,
|
||||
advanced: false,
|
||||
reqs,
|
||||
};
|
||||
|
||||
const driveSlice = createSlice({
|
||||
initialState,
|
||||
name: "drive",
|
||||
reducers: {
|
||||
setDrive: (state, action: PayloadAction<DriveProps>) => {
|
||||
state.rating = action.payload.rating;
|
||||
state.advanced = action.payload.advanced;
|
||||
},
|
||||
setDriveReqs: (state, action: PayloadAction<Reqs>) => {
|
||||
state.reqs = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = driveSlice;
|
||||
|
||||
/*
|
||||
// needs to be at the top level
|
||||
export const calculateDriveReqs = (store) =>
|
||||
createSelector(
|
||||
[
|
||||
(ship) => ship.reqs.mass,
|
||||
(ship) => ship.propulsion.drive.rating,
|
||||
(ship) => ship.propulsion.drive.advanced,
|
||||
],
|
||||
(ship_mass, rating, advanced) =>
|
||||
store.dispatch.setDriveReqs(calcDriveReqs(ship_mass, rating, advanced))
|
||||
);
|
||||
|
||||
export function calcDriveReqs(shipMass, rating, advanced = false) {
|
||||
const mass = Math.ceil(rating * 0.05 * shipMass);
|
||||
const cost = mass * (advanced ? 3 : 2);
|
||||
|
||||
return { mass, cost };
|
||||
}
|
||||
*/
|
@ -1,41 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
import { createSelector } from "reselect";
|
||||
|
||||
import reqs from "../reqs.js";
|
||||
|
||||
export const ftlTypes = ["none", "standard", "advanced"];
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { reqs },
|
||||
initial: {
|
||||
type: "none",
|
||||
uiTransform: "",
|
||||
},
|
||||
actions: {
|
||||
setFtl: null,
|
||||
setFtlReqs: null,
|
||||
},
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation("setFtl", (type) => u({ type }));
|
||||
dux.setMutation("setFtlReqs", (reqs) => u({ reqs }));
|
||||
|
||||
export function calcFtlReqs(type, shipMass) {
|
||||
if (type === "none") return { cost: 0, mass: 0 };
|
||||
|
||||
const mass = Math.ceil(shipMass / 10);
|
||||
|
||||
return {
|
||||
mass,
|
||||
cost: mass * (type === "advanced" ? 3 : 2),
|
||||
};
|
||||
}
|
||||
|
||||
// needs to be at the top level
|
||||
export const ftlReqsReaction = (store) =>
|
||||
createSelector(
|
||||
[(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass],
|
||||
(type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass))
|
||||
);
|
47
src/lib/shipDux/propulsion/ftl.ts
Normal file
47
src/lib/shipDux/propulsion/ftl.ts
Normal file
@ -0,0 +1,47 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
import { createSelector } from "reselect";
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
import { reqs, Reqs } from "../reqs.js";
|
||||
|
||||
export const ftlTypes = ["none", "standard", "advanced"] as const;
|
||||
type FtlType = typeof ftlTypes[number];
|
||||
|
||||
const initialState = {
|
||||
reqs,
|
||||
type: "none" as FtlType,
|
||||
};
|
||||
|
||||
const ftl = createSlice({
|
||||
name: "ftl",
|
||||
initialState,
|
||||
reducers: {
|
||||
setFtl: (state, { payload }: PayloadAction<FtlType>) => {
|
||||
state.type = payload;
|
||||
},
|
||||
setFtlReqs: (state, action: PayloadAction<Reqs>) => {
|
||||
state.reqs = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export function calcFtlReqs(type: FtlType, shipMass: number): Reqs {
|
||||
if (type === "none") return { cost: 0, mass: 0 };
|
||||
|
||||
const mass = Math.ceil(shipMass / 10);
|
||||
|
||||
return {
|
||||
mass,
|
||||
cost: mass * (type === "advanced" ? 3 : 2),
|
||||
};
|
||||
}
|
||||
|
||||
export const { actions, reducer } = ftl;
|
||||
|
||||
// needs to be at the top level
|
||||
export const ftlReqsReaction = (store) =>
|
||||
createSelector(
|
||||
[(ship) => ship.propulsion.ftl.type, (ship) => ship.reqs.mass],
|
||||
(type, shipMass) => store.dispatch.setFtlReqs(calcFtlReqs(type, shipMass))
|
||||
);
|
@ -1,13 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from 'updeep';
|
||||
|
||||
import drive from './drive.js';
|
||||
import ftl from './ftl.js';
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
drive, ftl
|
||||
},
|
||||
});
|
||||
|
||||
export default dux;
|
8
src/lib/shipDux/propulsion/index.ts
Normal file
8
src/lib/shipDux/propulsion/index.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { combineReducers } from "@reduxjs/toolkit";
|
||||
import * as drive from "./drive.js";
|
||||
import * as ftl from "./ftl.js";
|
||||
|
||||
export const reducer = combineReducers({
|
||||
drive: drive.reducer,
|
||||
ftl: ftl.reducer,
|
||||
});
|
@ -1,10 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
|
||||
const dux = new Updux({
|
||||
initial: {
|
||||
cost: 0,
|
||||
mass: 0,
|
||||
},
|
||||
});
|
||||
|
||||
export default dux;
|
6
src/lib/shipDux/reqs.ts
Normal file
6
src/lib/shipDux/reqs.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export type Reqs = {
|
||||
mass: number;
|
||||
cost: number;
|
||||
};
|
||||
|
||||
export const reqs = { cost: 0, mass: 0 };
|
@ -1,64 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import reqs from "../reqs.js";
|
||||
|
||||
const schema = {
|
||||
type: 'object',
|
||||
properties: {
|
||||
reqs: { type: 'object', properties: {
|
||||
cost: { type: 'number' },
|
||||
mass: { type: 'number' },
|
||||
} },
|
||||
layers: { type: 'array', items: 'number' }
|
||||
},
|
||||
examples: [
|
||||
{ reqs: { cost: 5, mass: 5 }, layers: [2,4 ] }
|
||||
]
|
||||
}
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
reqs,
|
||||
},
|
||||
initial: {
|
||||
layers: [],
|
||||
},
|
||||
actions: {
|
||||
setArmorLayers: null,
|
||||
setArmorRating: null,
|
||||
},
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation('setArmorRating', ({layer, rating}) => state => {
|
||||
let layers = [ ...state.layers ].map( (v,k) => k === layer-1 ? rating : v );
|
||||
|
||||
return { layers, reqs: calcArmorReqs(layers) }
|
||||
} );
|
||||
|
||||
dux.setMutation( 'setArmorLayers', nbrLayers => state => {
|
||||
|
||||
let layers = [...state.layers];
|
||||
|
||||
if( nbrLayers < state.layers.length )
|
||||
layers = [ ...state.layers ].slice(0,nbrLayers);
|
||||
|
||||
while( layers.length < nbrLayers ) {
|
||||
layers.push(0);
|
||||
}
|
||||
|
||||
return {
|
||||
layers,
|
||||
reqs: calcArmorReqs(layers),
|
||||
}
|
||||
});
|
||||
|
||||
function calcArmorReqs(layers) {
|
||||
const mass = 2* layers.reduce( (a,b) => a+ b,0 );
|
||||
const cost = 2* layers.map( (v,k) => v * (k+1) ).reduce( (a,b) => a+ b,0 );
|
||||
|
||||
return {
|
||||
mass, cost
|
||||
}
|
||||
}
|
35
src/lib/shipDux/structure/armor.ts
Normal file
35
src/lib/shipDux/structure/armor.ts
Normal file
@ -0,0 +1,35 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { Reqs, reqs } from "../reqs";
|
||||
|
||||
type Layer = number;
|
||||
|
||||
const initialState = {
|
||||
reqs,
|
||||
layers: [] as Layer[],
|
||||
};
|
||||
|
||||
const armor = createSlice({
|
||||
name: "armor",
|
||||
initialState,
|
||||
reducers: {
|
||||
setArmorRating: (state, action) => {
|
||||
state.layers[action.payload.layer - 1] = action.payload.rating;
|
||||
state.reqs = calcArmorReqs(state.layers);
|
||||
},
|
||||
setArmorLayers: (state, action: PayloadAction<number>) => {
|
||||
while (state.layers.length > action.payload) state.layers.pop();
|
||||
while (state.layers.length < action.payload) state.layers.push(0);
|
||||
state.reqs = calcArmorReqs(state.layers);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
function calcArmorReqs(layers: Layer[]): Reqs {
|
||||
const mass = 2 * layers.reduce((a, b) => a + b, 0);
|
||||
const cost = 2 * layers.map((v, k) => v * (k + 1)).reduce((a, b) => a + b, 0);
|
||||
|
||||
return {
|
||||
mass,
|
||||
cost,
|
||||
};
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from 'updeep';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import reqs from '../reqs.js';
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
reqs
|
||||
},
|
||||
initial: {
|
||||
space: 0,
|
||||
},
|
||||
actions: {
|
||||
setCargo: null,
|
||||
}
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation('setCargo', space => u({
|
||||
space,
|
||||
reqs: { mass: space }
|
||||
}));
|
||||
|
17
src/lib/shipDux/structure/cargo.ts
Normal file
17
src/lib/shipDux/structure/cargo.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs } from "../reqs";
|
||||
|
||||
const initialState = { space: 0, reqs };
|
||||
|
||||
const cargo = createSlice({
|
||||
name: "cargo",
|
||||
initialState,
|
||||
reducers: {
|
||||
setCargo: (state, action) => {
|
||||
state.space = action.payload;
|
||||
state.reqs = { cost: 0, mass: action.payload };
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = cargo;
|
@ -1,31 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from 'updeep';
|
||||
|
||||
import reqs from '../reqs.js';
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
reqs
|
||||
},
|
||||
initial: {
|
||||
rating: 0, min: 0, max: 0,
|
||||
},
|
||||
actions: {
|
||||
setShipMass: null,
|
||||
setHull: null,
|
||||
}
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation( 'setHull', rating => u({rating,
|
||||
reqs: {
|
||||
mass: rating, cost: 2 * rating
|
||||
}}) );
|
||||
|
||||
dux.setMutation( 'setShipMass', mass => state => {
|
||||
let {rating} = state;
|
||||
if(rating > mass) rating = mass;
|
||||
const min = Math.ceil(mass/10);
|
||||
if(rating < min) rating = min;
|
||||
return u({max: mass, min, rating}, state);
|
||||
})
|
34
src/lib/shipDux/structure/hull.ts
Normal file
34
src/lib/shipDux/structure/hull.ts
Normal file
@ -0,0 +1,34 @@
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
import { reqs } from "../reqs";
|
||||
|
||||
const initialState = {
|
||||
rating: 0,
|
||||
min: 0,
|
||||
max: 0,
|
||||
reqs,
|
||||
};
|
||||
|
||||
const hull = createSlice({
|
||||
name: "hull",
|
||||
initialState,
|
||||
reducers: {
|
||||
setHull: (state, action: PayloadAction<number>) => {
|
||||
state.rating = action.payload;
|
||||
state.reqs = {
|
||||
mass: action.payload,
|
||||
cost: 2 * action.payload,
|
||||
}
|
||||
},
|
||||
setShipMass: (state, action: PayloadAction<number>) => {
|
||||
const mass = action.payload;
|
||||
let { rating } = state;
|
||||
if (rating > mass) state.rating = mass;
|
||||
state.min = Math.ceil(mass / 10);
|
||||
if (state.rating < state.min) state.rating = state.min;
|
||||
state.max = mass;
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = hull;
|
@ -1,15 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
|
||||
import hull from "./hull.js";
|
||||
import screens from "./screens.js";
|
||||
import cargo from "./cargo.js";
|
||||
import armor from "./armor.js";
|
||||
import streamlining from "./streamlining.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { hull, screens, cargo, streamlining, armor },
|
||||
initial: {
|
||||
uiTransform: "",
|
||||
},
|
||||
});
|
||||
export default dux;
|
21
src/lib/shipDux/structure/index.ts
Normal file
21
src/lib/shipDux/structure/index.ts
Normal file
@ -0,0 +1,21 @@
|
||||
import { combineReducers } from "redux";
|
||||
import * as R from "remeda";
|
||||
|
||||
import * as hull from "./hull.js";
|
||||
import * as screens from "./screens.js";
|
||||
import * as cargo from "./cargo.js";
|
||||
import * as armor from "./armor.js";
|
||||
import * as streamlining from "./streamlining.js";
|
||||
|
||||
export const reducer = combineReducers(
|
||||
R.mapValues(
|
||||
{
|
||||
hull,
|
||||
screens,
|
||||
cargo,
|
||||
armor,
|
||||
streamlining,
|
||||
},
|
||||
R.prop("reducer")
|
||||
)
|
||||
);
|
42
src/lib/shipDux/structure/screen.ts
Normal file
42
src/lib/shipDux/structure/screen.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { createSelector, createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs } from "../reqs";
|
||||
|
||||
const initialState = {
|
||||
standard: 0,
|
||||
advanced: 0,
|
||||
reqs,
|
||||
};
|
||||
|
||||
const screen = createSlice({
|
||||
name: "screens",
|
||||
initialState,
|
||||
reducers: {
|
||||
setScreens(state, action) {
|
||||
state.standard = action.payload.standard;
|
||||
state.advanced = action.payload.advanced;
|
||||
},
|
||||
setScreensReqs(state, action) {
|
||||
state.reqs = action.payload;
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = screen;
|
||||
|
||||
export const screensReqsReaction = (store) =>
|
||||
createSelector(
|
||||
(ship) => ship.reqs.mass,
|
||||
(ship) => ship.structure.screens.standard,
|
||||
(ship) => ship.structure.screens.advanced,
|
||||
(...args) => store.dispatch.setScreensReqs(calcScreensReqs(...args))
|
||||
);
|
||||
|
||||
function calcScreensReqs(mass, standard, advanced) {
|
||||
const standard_mass = standard * Math.max(3, Math.ceil(0.05 * mass));
|
||||
const advanced_mass = advanced * Math.max(4, Math.ceil(0.075 * mass));
|
||||
|
||||
return {
|
||||
mass: standard_mass + advanced_mass,
|
||||
cost: 3 * standard_mass + 4 * advanced_mass,
|
||||
};
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from 'updeep';
|
||||
import { createSelector } from 'reselect';
|
||||
|
||||
import reqs from '../reqs.js';
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
reqs
|
||||
},
|
||||
initial: {
|
||||
standard: 0, advanced: 0,
|
||||
},
|
||||
actions: {
|
||||
setScreens: null,
|
||||
setScreensReqs: null,
|
||||
}
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation('setScreens', payload => u(payload));
|
||||
dux.setMutation('setScreensReqs', reqs => u({reqs}));
|
||||
|
||||
export const screensReqsReaction = store => createSelector(
|
||||
(ship) => ship.reqs.mass,
|
||||
(ship) => ship.structure.screens.standard,
|
||||
(ship) => ship.structure.screens.advanced,
|
||||
(...args) => store.dispatch.setScreensReqs(calcScreensReqs(...args)),
|
||||
);
|
||||
|
||||
function calcScreensReqs(mass,standard,advanced) {
|
||||
|
||||
const standard_mass = standard * Math.max(3, Math.ceil(0.05 * mass));
|
||||
const advanced_mass = advanced * Math.max(4, Math.ceil(0.075 * mass));
|
||||
|
||||
return {
|
||||
mass: standard_mass + advanced_mass,
|
||||
cost: 3 * standard_mass + 4 * advanced_mass,
|
||||
}
|
||||
}
|
@ -1,32 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import reqs from "../reqs.js";
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: {
|
||||
reqs,
|
||||
},
|
||||
initial: {
|
||||
type: "none",
|
||||
},
|
||||
actions: {
|
||||
setStreamlining: null,
|
||||
},
|
||||
});
|
||||
export default dux;
|
||||
|
||||
dux.setMutation("setStreamlining", ({ shipMass, type }) =>
|
||||
u({
|
||||
type,
|
||||
reqs: calcStreamliningReqs({ shipMass, type }),
|
||||
})
|
||||
);
|
||||
|
||||
function calcStreamliningReqs({ shipMass, type }) {
|
||||
const mass = Math.ceil(
|
||||
(shipMass * (type === "none" ? 0 : type === "partial" ? 5 : 10)) / 100
|
||||
);
|
||||
|
||||
return { mass, cost: 2 * mass };
|
||||
}
|
28
src/lib/shipDux/structure/streamlining.ts
Normal file
28
src/lib/shipDux/structure/streamlining.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import { createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs } from "../reqs";
|
||||
|
||||
const initialState = {
|
||||
type: "none",
|
||||
reqs,
|
||||
};
|
||||
|
||||
const streamlining = createSlice({
|
||||
name: "streamlining",
|
||||
initialState,
|
||||
reducers: {
|
||||
setStreamlining(state, action) {
|
||||
state.type = action.payload.type;
|
||||
state.reqs = calcStreamliningReqs(action.payload);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = streamlining;
|
||||
|
||||
function calcStreamliningReqs({ shipMass, type }) {
|
||||
const mass = Math.ceil(
|
||||
(shipMass * (type === "none" ? 0 : type === "partial" ? 5 : 10)) / 100
|
||||
);
|
||||
|
||||
return { mass, cost: 2 * mass };
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
import weapons from './weapons.js';
|
||||
|
||||
const reqs = { cost: 0, mass: 0 };
|
||||
|
||||
const dux = new Updux({
|
||||
subduxes: { weapons },
|
||||
initial: {
|
||||
firecons: {
|
||||
stations: 0,
|
||||
reqs,
|
||||
},
|
||||
adfc: { rating: 0, reqs },
|
||||
},
|
||||
actions: {
|
||||
setADFC: null,
|
||||
setFirecons: null,
|
||||
},
|
||||
});
|
||||
|
||||
dux.setMutation("setFirecons", (stations) =>
|
||||
u({
|
||||
firecons: {
|
||||
stations,
|
||||
reqs: {
|
||||
cost: 4 * stations,
|
||||
mass: stations,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
dux.setMutation("setADFC", (rating) =>
|
||||
u({
|
||||
adfc: {
|
||||
rating,
|
||||
reqs: {
|
||||
cost: 8 * rating,
|
||||
mass: 2 * rating,
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
export default dux;
|
45
src/lib/shipDux/weaponry/index.ts
Normal file
45
src/lib/shipDux/weaponry/index.ts
Normal file
@ -0,0 +1,45 @@
|
||||
import { combineReducers, createSlice } from "@reduxjs/toolkit";
|
||||
import { reqs } from "../reqs.js";
|
||||
import * as weapons from "./weapons.js";
|
||||
|
||||
const firecons = createSlice({
|
||||
name: "firecons",
|
||||
initialState: {
|
||||
stations: 0,
|
||||
reqs,
|
||||
},
|
||||
reducers: {
|
||||
setFirecons(state, action) {
|
||||
const stations = action.payload;
|
||||
state.stations = action.payload;
|
||||
state.reqs = {
|
||||
cost: 4 * stations,
|
||||
mass: stations,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const adfc = createSlice({
|
||||
name: "adfc",
|
||||
initialState: {
|
||||
rating: 0,
|
||||
reqs,
|
||||
},
|
||||
reducers: {
|
||||
setAdfc(state, action) {
|
||||
const rating = action.payload;
|
||||
state.rating = action.payload;
|
||||
state.reqs = {
|
||||
cost: 8 * rating,
|
||||
mass: 2 * rating,
|
||||
};
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const reducer = combineReducers({
|
||||
adfc: adfc.reducer,
|
||||
firecons: firecons.reducer,
|
||||
weapons: weapons.reducer,
|
||||
});
|
@ -1,122 +0,0 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
|
||||
const reqs = { cost: 0, mass: 0 };
|
||||
|
||||
export const weaponTypes = [
|
||||
{ name: 'beam', type: 'beam', reqs: beam_cost_mass, initial: {
|
||||
weaponClass: 1
|
||||
}},
|
||||
{ name: 'submunition pack', type: 'submunition', reqs: { mass:1, cost:3 },
|
||||
initial: { arc: 'F' }
|
||||
},
|
||||
{ name: 'point defence system', type: 'pds', reqs: {mass:1,cost:3}, initial: {}},
|
||||
{ name: 'scattergun', type: 'scattergun', reqs: { mass:1,cost:4 }, initial: {}},
|
||||
{ name: 'needle weapon', type: 'needle', reqs: { mass: 2, cost: 6 },
|
||||
initial: { arc: 'F' }},
|
||||
];
|
||||
|
||||
const dux = new Updux({
|
||||
initial: [],
|
||||
actions: {
|
||||
addWeapon: null,
|
||||
removeWeapon: null,
|
||||
setWeapon: null,
|
||||
},
|
||||
});
|
||||
|
||||
dux.setMutation('setWeapon', ({id,...rest}) => state => {
|
||||
console.log(id,rest,state);
|
||||
state = u.map( u.if( (w) => w.id === id,
|
||||
weapon => {
|
||||
return {
|
||||
id,
|
||||
...rest,
|
||||
reqs: weaponReqs(rest),
|
||||
}
|
||||
} ), state );
|
||||
console.log(state);
|
||||
return state;
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
dux.setMutation('removeWeapon', id => state => [
|
||||
...state.filter( (w) => w.id !== id )
|
||||
]);
|
||||
|
||||
dux.setMutation('addWeapon', type => state => {
|
||||
const initial = weaponTypes.find(w => w.type === type ).initial;
|
||||
return [
|
||||
...state,
|
||||
{
|
||||
id: state.length === 0 ? 1 : state[state.length -1]+1,
|
||||
type,
|
||||
reqs: weaponReqs({type,...initial}),
|
||||
...initial,
|
||||
}
|
||||
]
|
||||
});
|
||||
|
||||
function weaponReqs(weapon) {
|
||||
|
||||
const {reqs} = weaponTypes.find( wt => wt.type === weapon.type ) ||{};
|
||||
|
||||
if(!reqs) return {};
|
||||
|
||||
if( typeof reqs === 'function' ) return reqs(weapon);
|
||||
|
||||
return reqs;
|
||||
}
|
||||
|
||||
const isBroadside = arcs => {
|
||||
if( arcs.length !== 4 ) return false;
|
||||
|
||||
// that'd be A or F
|
||||
return !arcs.some( a => a.length === 1 );
|
||||
}
|
||||
|
||||
function beam_cost_mass({weaponClass, arcs}) {
|
||||
console.log({weaponClass,arcs})
|
||||
let mass;
|
||||
|
||||
if( weaponClass === 1 ) {
|
||||
mass = 1;
|
||||
}
|
||||
|
||||
if( weaponClass === 2 ) {
|
||||
mass = 2 + (arcs.length > 3 ? 1 : 0);
|
||||
}
|
||||
|
||||
|
||||
if( weaponClass == 3 ) {
|
||||
mass = 4;
|
||||
|
||||
if( isBroadside(arcs) ) {
|
||||
mass += 2;
|
||||
}
|
||||
else {
|
||||
mass += arcs.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( weaponClass == 4 ) {
|
||||
mass = 8;
|
||||
|
||||
if( isBroadside(arcs) ) {
|
||||
mass += 4;
|
||||
}
|
||||
else {
|
||||
mass += 2*(arcs.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
mass, cost: 3 * mass
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default dux;
|
129
src/lib/shipDux/weaponry/weapons.ts
Normal file
129
src/lib/shipDux/weaponry/weapons.ts
Normal file
@ -0,0 +1,129 @@
|
||||
import { Updux } from "updux";
|
||||
import u from "updeep";
|
||||
import { createSlice, PayloadAction } from "@reduxjs/toolkit";
|
||||
|
||||
export const weaponTypes = [
|
||||
{
|
||||
name: "beam",
|
||||
type: "beam",
|
||||
reqs: beamReqs,
|
||||
initial: {
|
||||
weaponClass: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "submunition pack",
|
||||
type: "submunition",
|
||||
reqs: { mass: 1, cost: 3 },
|
||||
initial: { arc: "F" },
|
||||
},
|
||||
{
|
||||
name: "point defence system",
|
||||
type: "pds",
|
||||
reqs: { mass: 1, cost: 3 },
|
||||
initial: {},
|
||||
},
|
||||
{
|
||||
name: "scattergun",
|
||||
type: "scattergun",
|
||||
reqs: { mass: 1, cost: 4 },
|
||||
initial: {},
|
||||
},
|
||||
{
|
||||
name: "needle weapon",
|
||||
type: "needle",
|
||||
reqs: { mass: 2, cost: 6 },
|
||||
initial: { arc: "F" },
|
||||
},
|
||||
];
|
||||
|
||||
const weaponsSlice = createSlice({
|
||||
name: "weapons",
|
||||
initialState: [] as {
|
||||
id: number;
|
||||
weaponClass: string;
|
||||
arcs?: unknown[];
|
||||
type: string;
|
||||
}[],
|
||||
reducers: {
|
||||
removeWeapon: (state, action: PayloadAction<number>) => {
|
||||
return state.filter(({ id }) => id !== action.payload);
|
||||
},
|
||||
setWeapon: (state, action: PayloadAction<{ id: number }>) => {
|
||||
return state.map((weapon) => {
|
||||
if (weapon.id !== action.payload.id) return weapon;
|
||||
return {
|
||||
...action.payload,
|
||||
reqs: weaponReqs(action.payload),
|
||||
};
|
||||
}) as any;
|
||||
},
|
||||
addWeapon: (state, action: PayloadAction<{ type: string }>) => {
|
||||
const initial = weaponTypes.find(
|
||||
(w) => w.type === action.payload.type
|
||||
).initial;
|
||||
state.push({
|
||||
id: state.length + 1,
|
||||
type: action.payload.type,
|
||||
reqs: weaponReqs({ type: action.payload.type, ...initial }),
|
||||
...initial,
|
||||
} as any);
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const { actions, reducer } = weaponsSlice;
|
||||
|
||||
function weaponReqs(weapon) {
|
||||
const { reqs } = weaponTypes.find((wt) => wt.type === weapon.type) || {};
|
||||
|
||||
if (!reqs) return {};
|
||||
|
||||
if (typeof reqs === "function") return reqs(weapon);
|
||||
|
||||
return reqs;
|
||||
}
|
||||
|
||||
const isBroadside = (arcs) => {
|
||||
if (arcs.length !== 4) return false;
|
||||
|
||||
// that'd be A or F
|
||||
return !arcs.some((a) => a.length === 1);
|
||||
};
|
||||
|
||||
function beamReqs({ weaponClass, arcs }) {
|
||||
let mass;
|
||||
|
||||
if (weaponClass === 1) {
|
||||
mass = 1;
|
||||
}
|
||||
|
||||
if (weaponClass === 2) {
|
||||
mass = 2 + (arcs.length > 3 ? 1 : 0);
|
||||
}
|
||||
|
||||
if (weaponClass == 3) {
|
||||
mass = 4;
|
||||
|
||||
if (isBroadside(arcs)) {
|
||||
mass += 2;
|
||||
} else {
|
||||
mass += arcs.length - 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (weaponClass == 4) {
|
||||
mass = 8;
|
||||
|
||||
if (isBroadside(arcs)) {
|
||||
mass += 4;
|
||||
} else {
|
||||
mass += 2 * (arcs.length - 1);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
mass,
|
||||
cost: 3 * mass,
|
||||
};
|
||||
}
|
Loading…
Reference in New Issue
Block a user