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,7 +1,7 @@
|
|||||||
import { Updux } from "updux";
|
import { Updux } from "updux";
|
||||||
import u from "updeep";
|
import u from "updeep";
|
||||||
|
|
||||||
import carrier from './carrier.js';
|
import carrier from "./carrier.js";
|
||||||
|
|
||||||
const dux = new Updux({
|
const dux = new Updux({
|
||||||
actions: {
|
actions: {
|
||||||
@ -19,8 +19,10 @@ const dux = new Updux({
|
|||||||
|
|
||||||
dux.setMutation("setShipType", (shipType) => u({ shipType }));
|
dux.setMutation("setShipType", (shipType) => u({ shipType }));
|
||||||
dux.setMutation("setShipClass", (shipClass) => u({ shipClass }));
|
dux.setMutation("setShipClass", (shipClass) => u({ shipClass }));
|
||||||
dux.setMutation('setCarrierBays', (bays) => u({
|
dux.setMutation("setCarrierBays", (bays) =>
|
||||||
|
u({
|
||||||
isCarrier: bays > 0,
|
isCarrier: bays > 0,
|
||||||
}))
|
})
|
||||||
|
);
|
||||||
|
|
||||||
export default dux;
|
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