got all subduxes in
This commit is contained in:
parent
0e76cdd4d3
commit
8bb1955dff
@ -2,44 +2,26 @@ import { combineReducers, createSlice } from "@reduxjs/toolkit";
|
|||||||
import { reqs } from "../reqs.js";
|
import { reqs } from "../reqs.js";
|
||||||
import * as weapons from "./weapons.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({
|
const adfc = createSlice({
|
||||||
name: "adfc",
|
name: "adfc",
|
||||||
initialState: {
|
initialState: {
|
||||||
rating: 0,
|
rating: 0,
|
||||||
reqs,
|
reqs,
|
||||||
},
|
},
|
||||||
reducers: {
|
reducers: {
|
||||||
setAdfc(state, action) {
|
setAdfc(state, action) {
|
||||||
const rating = action.payload;
|
const rating = action.payload;
|
||||||
state.rating = action.payload;
|
state.rating = action.payload;
|
||||||
state.reqs = {
|
state.reqs = {
|
||||||
cost: 8 * rating,
|
cost: 8 * rating,
|
||||||
mass: 2 * rating,
|
mass: 2 * rating,
|
||||||
};
|
};
|
||||||
},
|
|
||||||
},
|
},
|
||||||
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const reducer = combineReducers({
|
export const reducer = combineReducers({
|
||||||
adfc: adfc.reducer,
|
adfc: adfc.reducer,
|
||||||
firecons: firecons.reducer,
|
firecons: firecons.reducer,
|
||||||
weapons: weapons.reducer,
|
weapons: weapons.reducer,
|
||||||
});
|
});
|
||||||
|
@ -36,4 +36,15 @@ test("kicking the tires", () => {
|
|||||||
cost: 0,
|
cost: 0,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
store.dispatch.setNbrArmorLayers(1);
|
||||||
|
store.dispatch.setArmorRating(1, 3);
|
||||||
|
|
||||||
|
expect(store.getState().structure.armor).toEqual({
|
||||||
|
layers: [3],
|
||||||
|
reqs: {
|
||||||
|
cost: 6,
|
||||||
|
mass: 6,
|
||||||
|
},
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -13,27 +13,48 @@ import { calcStreamliningReqs } from "./ship/structure/rules";
|
|||||||
import { cargoDux } from "./ship/structure/cargo";
|
import { cargoDux } from "./ship/structure/cargo";
|
||||||
import { hullDux } from "./ship/structure/hull";
|
import { hullDux } from "./ship/structure/hull";
|
||||||
import { screensDux, screensReqsReaction } from "./ship/structure/screens";
|
import { screensDux, screensReqsReaction } from "./ship/structure/screens";
|
||||||
|
import { armorDux } from "./ship/structure/armor";
|
||||||
|
import { fireconsDux } from "./ship/weaponry/firecons";
|
||||||
|
import { adfcDux } from "./ship/weaponry/adfc";
|
||||||
|
import { weaponsDux } from "./ship/weaponry/weapons";
|
||||||
|
|
||||||
|
process.env.UPDEEP_MODE = "dangerously_never_freeze";
|
||||||
|
|
||||||
|
const structure = new Updux({
|
||||||
|
initialState: {},
|
||||||
|
subduxes: {
|
||||||
|
streamlining,
|
||||||
|
cargo: cargoDux,
|
||||||
|
hull: hullDux,
|
||||||
|
screens: screensDux,
|
||||||
|
armor: armorDux,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const propulsion = new Updux({
|
||||||
|
initialState: {},
|
||||||
|
subduxes: {
|
||||||
|
ftl,
|
||||||
|
drive,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const weaponry = new Updux({
|
||||||
|
initialState: {},
|
||||||
|
subduxes: {
|
||||||
|
adfc: adfcDux,
|
||||||
|
firecons: fireconsDux,
|
||||||
|
weapons: weaponsDux,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
const shipDux = new Updux({
|
const shipDux = new Updux({
|
||||||
subduxes: {
|
subduxes: {
|
||||||
identification,
|
identification,
|
||||||
structure: new Updux({
|
structure,
|
||||||
initialState: {},
|
propulsion,
|
||||||
subduxes: {
|
|
||||||
streamlining,
|
|
||||||
cargo: cargoDux,
|
|
||||||
hull: hullDux,
|
|
||||||
screens: screensDux,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
propulsion: new Updux({
|
|
||||||
initialState: {},
|
|
||||||
subduxes: {
|
|
||||||
ftl,
|
|
||||||
drive,
|
|
||||||
},
|
|
||||||
}),
|
|
||||||
carrier: carrierDux,
|
carrier: carrierDux,
|
||||||
|
weaponry,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
52
src/lib/store/ship/structure/armor.ts
Normal file
52
src/lib/store/ship/structure/armor.ts
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
import { reqs, type Reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import { createSelector } from "reselect";
|
||||||
|
import prepare from "immer";
|
||||||
|
|
||||||
|
type Layer = number;
|
||||||
|
|
||||||
|
const initialState = {
|
||||||
|
reqs,
|
||||||
|
layers: [] as Layer[],
|
||||||
|
};
|
||||||
|
|
||||||
|
const setNbrArmorLayers = createPayloadAction<number>("setNbrArmorLayers");
|
||||||
|
const setArmorRating = createPayloadAction(
|
||||||
|
"setArmorRating",
|
||||||
|
(id: number, rating: number) => ({ index: id - 1, rating })
|
||||||
|
);
|
||||||
|
|
||||||
|
export const armorDux = new Updux({
|
||||||
|
initialState,
|
||||||
|
actions: { setNbrArmorLayers, setArmorRating },
|
||||||
|
});
|
||||||
|
|
||||||
|
armorDux.addMutation(setArmorRating, ({ index, rating }) =>
|
||||||
|
prepare((state) => {
|
||||||
|
state.layers[index] = rating;
|
||||||
|
state.reqs = calcArmorReqs(state.layers);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
armorDux.addMutation(setNbrArmorLayers, (nbrLayers) =>
|
||||||
|
prepare((state) => {
|
||||||
|
while (state.layers.length > nbrLayers) {
|
||||||
|
state.layers.pop();
|
||||||
|
}
|
||||||
|
while (state.layers.length < nbrLayers) {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
20
src/lib/store/ship/weaponry/adfc.ts
Normal file
20
src/lib/store/ship/weaponry/adfc.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
|
||||||
|
export const adfcDux = new Updux({
|
||||||
|
initialState: {
|
||||||
|
rating: 0,
|
||||||
|
reqs,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setADFC: (rating: number) => rating,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
adfcDux.addMutation(adfcDux.actions.setADFC, (rating) =>
|
||||||
|
u({
|
||||||
|
rating,
|
||||||
|
reqs: { cost: 8 * rating, mass: 2 * rating },
|
||||||
|
})
|
||||||
|
);
|
20
src/lib/store/ship/weaponry/firecons.ts
Normal file
20
src/lib/store/ship/weaponry/firecons.ts
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
import { reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux, { createPayloadAction } from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
|
||||||
|
export const fireconsDux = new Updux({
|
||||||
|
initialState: {
|
||||||
|
stations: 0,
|
||||||
|
reqs,
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setFirecons: (stations: number) => stations,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
fireconsDux.addMutation(fireconsDux.actions.setFirecons, (stations) =>
|
||||||
|
u({
|
||||||
|
stations,
|
||||||
|
reqs: { cost: 4 * stations, mass: stations },
|
||||||
|
})
|
||||||
|
);
|
90
src/lib/store/ship/weaponry/rules.ts
Normal file
90
src/lib/store/ship/weaponry/rules.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import type { Reqs } from "$lib/shipDux/reqs";
|
||||||
|
|
||||||
|
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" },
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
export function weaponReqs(weapon): Reqs {
|
||||||
|
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,
|
||||||
|
};
|
||||||
|
}
|
46
src/lib/store/ship/weaponry/weapons.ts
Normal file
46
src/lib/store/ship/weaponry/weapons.ts
Normal file
@ -0,0 +1,46 @@
|
|||||||
|
import type { Reqs } from "$lib/shipDux/reqs";
|
||||||
|
import Updux from "updux";
|
||||||
|
import u from "@yanick/updeep-remeda";
|
||||||
|
import * as R from "remeda";
|
||||||
|
import { weaponReqs } from "./rules";
|
||||||
|
import { nanoid } from "@reduxjs/toolkit";
|
||||||
|
|
||||||
|
type Weapon = {
|
||||||
|
weaponClass: string;
|
||||||
|
arcs?: unknown[];
|
||||||
|
type: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type IndexedWeapon = { id: string; reqs: Reqs; specs: Weapon };
|
||||||
|
|
||||||
|
export const weaponsDux = new Updux({
|
||||||
|
initialState: [] as IndexedWeapon[],
|
||||||
|
actions: {
|
||||||
|
removeWeapon: (id: string) => id,
|
||||||
|
setWeapon: (id: string, specs: Weapon) => ({ id, specs }),
|
||||||
|
addWeapon: (specs: Weapon) => specs,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
weaponsDux.addMutation(weaponsDux.actions.removeWeapon, (id) =>
|
||||||
|
R.reject(u.matches({ id }))
|
||||||
|
);
|
||||||
|
|
||||||
|
weaponsDux.addMutation(
|
||||||
|
weaponsDux.actions.setWeapon,
|
||||||
|
({ id, specs }) =>
|
||||||
|
(state) => {
|
||||||
|
const weapon = state.find(u.matches({ id }));
|
||||||
|
if (!weapon) return;
|
||||||
|
weapon.specs = specs;
|
||||||
|
weapon.reqs = weaponReqs(specs);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
weaponsDux.addMutation(weaponsDux.actions.addWeapon, (specs) => (state) => {
|
||||||
|
state.push({
|
||||||
|
id: nanoid(),
|
||||||
|
specs,
|
||||||
|
reqs: weaponReqs(specs),
|
||||||
|
});
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user